diff options
author | Vic Yang <victoryang@chromium.org> | 2014-10-09 14:04:32 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-10-15 20:49:35 +0000 |
commit | 4a9cabc3f9e8cfbeee857180c8a0b400ef7c8092 (patch) | |
tree | 6cdc15de6e9995be04351870030ef334fee9459d | |
parent | b8f73a451d9f0e62aba43dab1184bc1352ee968f (diff) | |
download | chrome-ec-4a9cabc3f9e8cfbeee857180c8a0b400ef7c8092.tar.gz |
Factor out common flash code for STM32F and STM32F0
This is a preparatory work for the following change for write protection
support on STM32F0.
BUG=chrome-os-partner:32745
TEST=make buildall
BRANCH=samus
Change-Id: Ic4deea06e26c4a6ac024a5388e1a5783b40e9876
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/222660
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | chip/stm32/build.mk | 3 | ||||
-rw-r--r-- | chip/stm32/flash-f.c | 448 | ||||
-rw-r--r-- | chip/stm32/flash-stm32f.c | 430 | ||||
-rw-r--r-- | chip/stm32/flash-stm32l.c | 7 | ||||
-rw-r--r-- | common/flash.c | 2 | ||||
-rw-r--r-- | include/flash.h | 20 |
7 files changed, 486 insertions, 431 deletions
@@ -92,14 +92,17 @@ _rw_size_str:=$(shell echo "CONFIG_FW_RW_SIZE" | $(CPP) $(CPPFLAGS) -P \ -Ichip/$(CHIP) -Iboard/$(BOARD) -imacros include/config.h) _rw_size:=$(shell echo "$$(($(_rw_size_str)))") +$(eval BOARD_$(UC_BOARD)=y) +$(eval CHIP_$(UC_CHIP)=y) +$(eval CHIP_VARIANT_$(UC_CHIP_VARIANT)=y) +$(eval CHIP_FAMILY_$(UC_CHIP_FAMILY)=y) + # Get build configuration from sub-directories # Note that this re-includes the board and chip makefiles include board/$(BOARD)/build.mk include chip/$(CHIP)/build.mk include core/$(CORE)/build.mk -$(eval BOARD_$(UC_BOARD)=y) - include common/build.mk include driver/build.mk include power/build.mk diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index 1c5081a5da..3e62c9301a 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -35,6 +35,9 @@ chip-$(HAS_TASK_CONSOLE)+=uart.o chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o chip-$(HAS_TASK_POWERLED)+=power_led.o chip-$(CONFIG_FLASH)+=flash-$(CHIP_FAMILY).o +chip-$(CHIP_FAMILY_STM32F)+=flash-f.o +chip-$(CHIP_FAMILY_STM32F0)+=flash-f.o +chip-$(CHIP_FAMILY_STM32F3)+=flash-f.o chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o chip-$(CONFIG_PWM)+=pwm.o chip-$(CONFIG_USB)+=usb.o usb_endpoints.o diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c new file mode 100644 index 0000000000..29e2c062d7 --- /dev/null +++ b/chip/stm32/flash-f.c @@ -0,0 +1,448 @@ +/* Copyright 2014 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. + */ + +/* Common flash memory module for STM32F and STM32F0 */ + +#include "battery.h" +#include "console.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 16000 +#define FLASH_TIMEOUT_LOOP \ + (FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP) + +/* Flash unlocking keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* Lock bits for FLASH_CR register */ +#define PG (1<<0) +#define PER (1<<1) +#define OPTPG (1<<4) +#define OPTER (1<<5) +#define STRT (1<<6) +#define CR_LOCK (1<<7) +#define PRG_LOCK 0 +#define OPT_LOCK (1<<9) + +static int write_optb(int byte, uint8_t value); + +static int wait_busy(void) +{ + int timeout = FLASH_TIMEOUT_LOOP; + while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0) + udelay(CYCLE_PER_FLASH_LOOP); + 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 & CR_LOCK) { + STM32_FLASH_KEYR = KEY1; + STM32_FLASH_KEYR = KEY2; + } + /* unlock option memory if required */ + if ((locks & OPT_LOCK) && !(STM32_FLASH_CR & OPT_LOCK)) { + STM32_FLASH_OPTKEYR = KEY1; + STM32_FLASH_OPTKEYR = KEY2; + } + + /* Re-enable bus fault handler */ + ignore_bus_fault(0); + + return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ? + EC_ERROR_UNKNOWN : EC_SUCCESS; +} + +static void lock(void) +{ + STM32_FLASH_CR = CR_LOCK; +} + +/* + * Option byte organization + * + * [31:24] [23:16] [15:8] [7:0] + * + * 0x1FFF_F800 nUSER USER nRDP RDP + * + * 0x1FFF_F804 nData1 Data1 nData0 Data0 + * + * 0x1FFF_F808 nWRP1 WRP1 nWRP0 WRP0 + * + * 0x1FFF_F80C nWRP3 WRP2 nWRP2 WRP2 + * + * Note that the variable with n prefix means the complement. + */ +static uint8_t read_optb(int byte) +{ + return *(uint8_t *)(STM32_OPTB_BASE + byte); +} + +static int erase_optb(void) +{ + int rv; + + rv = wait_busy(); + if (rv) + return rv; + + rv = unlock(OPT_LOCK); + if (rv) + return rv; + + /* Must be set in 2 separate lines. */ + STM32_FLASH_CR |= OPTER; + STM32_FLASH_CR |= STRT; + + rv = wait_busy(); + if (rv) + return rv; + lock(); + + return EC_SUCCESS; +} + +/* + * Since the option byte erase is WHOLE erase, this function is to keep + * rest of bytes, but make this byte 0xff. + * Note that this could make a recursive call to write_optb(). + */ +static int preserve_optb(int byte) +{ + int i, rv; + uint8_t optb[8]; + + /* The byte has been reset, no need to run preserve. */ + if (*(uint16_t *)(STM32_OPTB_BASE + byte) == 0xffff) + return EC_SUCCESS; + + for (i = 0; i < ARRAY_SIZE(optb); ++i) + optb[i] = read_optb(i * 2); + + optb[byte / 2] = 0xff; + + rv = erase_optb(); + if (rv) + return rv; + for (i = 0; i < ARRAY_SIZE(optb); ++i) { + rv = write_optb(i * 2, optb[i]); + if (rv) + return rv; + } + + return EC_SUCCESS; +} + +static int write_optb(int byte, uint8_t value) +{ + volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); + int rv; + + rv = wait_busy(); + if (rv) + return rv; + + /* The target byte is the value we want to write. */ + if (*(uint8_t *)hword == value) + return EC_SUCCESS; + + /* Try to erase that byte back to 0xff. */ + rv = preserve_optb(byte); + if (rv) + return rv; + + /* The value is 0xff after erase. No need to write 0xff again. */ + if (value == 0xff) + return EC_SUCCESS; + + rv = unlock(OPT_LOCK); + if (rv) + return rv; + + /* set OPTPG bit */ + STM32_FLASH_CR |= OPTPG; + + *hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value; + + /* reset OPTPG bit */ + STM32_FLASH_CR &= ~OPTPG; + + rv = wait_busy(); + if (rv) + return rv; + lock(); + + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Physical layer APIs */ + +int flash_physical_write(int offset, int size, const char *data) +{ + uint16_t *address = (uint16_t *)(CONFIG_FLASH_BASE + offset); + int res = EC_SUCCESS; + int i; + + if (unlock(PRG_LOCK) != EC_SUCCESS) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + + /* set PG bit */ + STM32_FLASH_CR |= PG; + + for (; size > 0; size -= sizeof(uint16_t)) { + /* + * Reload the watchdog timer to avoid watchdog reset when doing + * long writing with interrupt disabled. + */ + watchdog_reload(); + + /* wait to be ready */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + i++) + ; + + /* write the half word */ + *address++ = data[0] + (data[1] << 8); + data += 2; + + /* Wait for writes to complete */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + i++) + ; + + 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 & 0x14) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + } + +exit_wr: + /* Disable PG bit */ + STM32_FLASH_CR &= ~PG; + + lock(); + + return res; +} + +int flash_physical_erase(int offset, int size) +{ + int res = EC_SUCCESS; + + if (unlock(PRG_LOCK) != EC_SUCCESS) + return EC_ERROR_UNKNOWN; + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + + /* set PER bit */ + STM32_FLASH_CR |= PER; + + for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, + offset += CONFIG_FLASH_ERASE_SIZE) { + timestamp_t deadline; + + /* Do nothing if already erased */ + if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) + continue; + + /* select page to erase */ + STM32_FLASH_AR = CONFIG_FLASH_BASE + offset; + + /* set STRT bit : start erase */ + STM32_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 & 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 & 0x14) { + res = EC_ERROR_UNKNOWN; + goto exit_er; + } + } + +exit_er: + /* reset PER bit */ + STM32_FLASH_CR &= ~PER; + + lock(); + + return res; +} + +static int flash_physical_get_protect_at_boot(int block) +{ + uint8_t val = read_optb(STM32_OPTB_WRP_OFF(block/8)); + return (!(val & (1 << (block % 8)))) ? 1 : 0; +} + +int flash_physical_protect_at_boot(enum flash_wp_range range) +{ + int block; + int i; + int original_val[4], val[4]; + enum flash_wp_range cur_range; + + for (i = 0; i < 4; ++i) + original_val[i] = val[i] = read_optb(i * 2 + 8); + + for (block = RO_BANK_OFFSET; + block < RO_BANK_OFFSET + PHYSICAL_BANKS; + block++) { + int byte_off = STM32_OPTB_WRP_OFF(block/8) / 2 - 4; + + if (block >= RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT) + cur_range = FLASH_WP_ALL; + else + cur_range = FLASH_WP_RO; + + if (cur_range <= range) + val[byte_off] = val[byte_off] & (~(1 << (block % 8))); + else + val[byte_off] = val[byte_off] | (1 << (block % 8)); + } + + for (i = 0; i < 4; ++i) + if (original_val[i] != val[i]) + write_optb(i * 2 + 8, val[i]); + + 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 = flash_get_protect(); + int i; + int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0; + int ro_wp_region_start = RO_BANK_OFFSET; + int ro_wp_region_end = + RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT; + + for (i = ro_wp_region_start; i < ro_wp_region_end; i++) + if (flash_physical_get_protect_at_boot(i) != ro_at_boot) + return 1; + return 0; +} + +static void unprotect_all_blocks(void) +{ + int i; + for (i = 4; i < 8; ++i) + write_optb(i * 2, 0xff); +} + +/*****************************************************************************/ +/* High-level APIs */ + +int flash_pre_init(void) +{ + uint32_t prot_flags = flash_get_protect(); + int need_reset = 0; + + if (flash_physical_restore_state()) + 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_physical_protect_at_boot(FLASH_WP_RO); + 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. + */ + flash_protect_ro_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 (need_reset) + system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); + + return EC_SUCCESS; +} diff --git a/chip/stm32/flash-stm32f.c b/chip/stm32/flash-stm32f.c index 7c41498377..68e6b7a8e6 100644 --- a/chip/stm32/flash-stm32f.c +++ b/chip/stm32/flash-stm32f.c @@ -1,46 +1,16 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* Copyright 2014 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 "battery.h" -#include "console.h" +#include "common.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 16000 -#define FLASH_TIMEOUT_LOOP \ - (FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP) - -/* Flash unlocking keys */ -#define KEY1 0x45670123 -#define KEY2 0xCDEF89AB - -/* Lock bits for FLASH_CR register */ -#define PG (1<<0) -#define PER (1<<1) -#define OPTPG (1<<4) -#define OPTER (1<<5) -#define STRT (1<<6) -#define CR_LOCK (1<<7) -#define PRG_LOCK 0 -#define OPT_LOCK (1<<9) +#include "panic.h" /* Flag indicating whether we have locked down entire flash */ static int entire_flash_locked; @@ -57,301 +27,14 @@ struct flash_wp_state { int entire_flash_locked; }; -static int write_optb(int byte, uint8_t value); - -static int wait_busy(void) -{ - int timeout = FLASH_TIMEOUT_LOOP; - while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0) - udelay(CYCLE_PER_FLASH_LOOP); - 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 & CR_LOCK) { - STM32_FLASH_KEYR = KEY1; - STM32_FLASH_KEYR = KEY2; - } - /* unlock option memory if required */ - if ((locks & OPT_LOCK) && !(STM32_FLASH_CR & OPT_LOCK)) { - STM32_FLASH_OPTKEYR = KEY1; - STM32_FLASH_OPTKEYR = KEY2; - } - - /* Re-enable bus fault handler */ - ignore_bus_fault(0); - - return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ? - EC_ERROR_UNKNOWN : EC_SUCCESS; -} - -static void lock(void) -{ - STM32_FLASH_CR = CR_LOCK; -} - -/* - * Option byte organization - * - * [31:24] [23:16] [15:8] [7:0] - * - * 0x1FFF_F800 nUSER USER nRDP RDP - * - * 0x1FFF_F804 nData1 Data1 nData0 Data0 - * - * 0x1FFF_F808 nWRP1 WRP1 nWRP0 WRP0 - * - * 0x1FFF_F80C nWRP3 WRP2 nWRP2 WRP2 - * - * Note that the variable with n prefix means the complement. - */ -static uint8_t read_optb(int byte) -{ - return *(uint8_t *)(STM32_OPTB_BASE + byte); -} - -static int erase_optb(void) -{ - int rv; - - rv = wait_busy(); - if (rv) - return rv; - - rv = unlock(OPT_LOCK); - if (rv) - return rv; - - /* Must be set in 2 separate lines. */ - STM32_FLASH_CR |= OPTER; - STM32_FLASH_CR |= STRT; - - rv = wait_busy(); - if (rv) - return rv; - lock(); - - return EC_SUCCESS; -} - -/* - * Since the option byte erase is WHOLE erase, this function is to keep - * rest of bytes, but make this byte 0xff. - * Note that this could make a recursive call to write_optb(). - */ -static int preserve_optb(int byte) -{ - int i, rv; - uint8_t optb[8]; - - /* The byte has been reset, no need to run preserve. */ - if (*(uint16_t *)(STM32_OPTB_BASE + byte) == 0xffff) - return EC_SUCCESS; - - for (i = 0; i < ARRAY_SIZE(optb); ++i) - optb[i] = read_optb(i * 2); - - optb[byte / 2] = 0xff; - - rv = erase_optb(); - if (rv) - return rv; - for (i = 0; i < ARRAY_SIZE(optb); ++i) { - rv = write_optb(i * 2, optb[i]); - if (rv) - return rv; - } - - return EC_SUCCESS; -} - -static int write_optb(int byte, uint8_t value) -{ - volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); - int rv; - - rv = wait_busy(); - if (rv) - return rv; - - /* The target byte is the value we want to write. */ - if (*(uint8_t *)hword == value) - return EC_SUCCESS; - - /* Try to erase that byte back to 0xff. */ - rv = preserve_optb(byte); - if (rv) - return rv; - - /* The value is 0xff after erase. No need to write 0xff again. */ - if (value == 0xff) - return EC_SUCCESS; - - rv = unlock(OPT_LOCK); - if (rv) - return rv; - - /* set OPTPG bit */ - STM32_FLASH_CR |= OPTPG; - - *hword = value; - - /* reset OPTPG bit */ - STM32_FLASH_CR &= ~OPTPG; - - rv = wait_busy(); - if (rv) - return rv; - lock(); - - return EC_SUCCESS; -} - /*****************************************************************************/ /* Physical layer APIs */ -int flash_physical_write(int offset, int size, const char *data) -{ - uint16_t *address = (uint16_t *)(CONFIG_FLASH_BASE + offset); - int res = EC_SUCCESS; - int i; - - if (unlock(PRG_LOCK) != EC_SUCCESS) { - res = EC_ERROR_UNKNOWN; - goto exit_wr; - } - - /* Clear previous error status */ - STM32_FLASH_SR = 0x34; - - /* set PG bit */ - STM32_FLASH_CR |= PG; - - for (; size > 0; size -= sizeof(uint16_t)) { - /* - * Reload the watchdog timer to avoid watchdog reset when doing - * long writing with interrupt disabled. - */ - watchdog_reload(); - - /* wait to be ready */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); - i++) - ; - - /* write the half word */ - *address++ = data[0] + (data[1] << 8); - data += 2; - - /* Wait for writes to complete */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); - i++) - ; - - 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 & 0x14) { - res = EC_ERROR_UNKNOWN; - goto exit_wr; - } - } - -exit_wr: - /* Disable PG bit */ - STM32_FLASH_CR &= ~PG; - - lock(); - - return res; -} - -int flash_physical_erase(int offset, int size) -{ - int res = EC_SUCCESS; - - if (unlock(PRG_LOCK) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - /* Clear previous error status */ - STM32_FLASH_SR = 0x34; - - /* set PER bit */ - STM32_FLASH_CR |= PER; - - for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, - offset += CONFIG_FLASH_ERASE_SIZE) { - timestamp_t deadline; - - /* Do nothing if already erased */ - if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) - continue; - - /* select page to erase */ - STM32_FLASH_AR = CONFIG_FLASH_BASE + offset; - - /* set STRT bit : start erase */ - STM32_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 & 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 & 0x14) { - res = EC_ERROR_UNKNOWN; - goto exit_er; - } - } - -exit_er: - /* reset PER bit */ - STM32_FLASH_CR &= ~PER; - - lock(); - - return res; -} - int flash_physical_get_protect(int block) { return entire_flash_locked || !(STM32_FLASH_WRPR & (1 << block)); } -static int flash_physical_get_protect_at_boot(int block) -{ - uint8_t val = read_optb(STM32_OPTB_WRP_OFF(block/8)); - return (!(val & (1 << (block % 8)))) ? 1 : 0; -} - uint32_t flash_physical_get_protect_flags(void) { uint32_t flags = 0; @@ -363,32 +46,6 @@ uint32_t flash_physical_get_protect_flags(void) return flags; } -int flash_physical_protect_ro_at_boot(int enable) -{ - int block; - int i; - int original_val[4], val[4]; - - for (i = 0; i < 4; ++i) - original_val[i] = val[i] = read_optb(i * 2 + 8); - - for (block = RO_BANK_OFFSET; - block < RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT; - block++) { - int byte_off = STM32_OPTB_WRP_OFF(block/8) / 2 - 4; - if (enable) - val[byte_off] = val[byte_off] & (~(1 << (block % 8))); - else - val[byte_off] = val[byte_off] | (1 << (block % 8)); - } - - for (i = 0; i < 4; ++i) - if (original_val[i] != val[i]) - write_optb(i * 2 + 8, val[i]); - - return EC_SUCCESS; -} - int flash_physical_protect_now(int all) { if (all) { @@ -410,44 +67,11 @@ int flash_physical_protect_now(int all) } } -/** - * 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 = flash_get_protect(); - int i; - int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0; - int ro_wp_region_start = RO_BANK_OFFSET; - int ro_wp_region_end = - RO_BANK_OFFSET + RO_BANK_COUNT + PSTATE_BANK_COUNT; - - for (i = ro_wp_region_start; i < ro_wp_region_end; i++) - if (flash_physical_get_protect_at_boot(i) != ro_at_boot) - return 1; - return 0; -} - -static void unprotect_all_blocks(void) -{ - int i; - for (i = 4; i < 8; ++i) - write_optb(i * 2, 0xff); -} - -/*****************************************************************************/ -/* High-level APIs */ - -int flash_pre_init(void) +int flash_physical_restore_state(void) { uint32_t reset_flags = system_get_reset_flags(); - uint32_t prot_flags = flash_get_protect(); - int need_reset = 0; - const struct flash_wp_state *prev; int version, size; + const struct flash_wp_state *prev; /* * If we have already jumped between images, an earlier image could @@ -459,50 +83,10 @@ int flash_pre_init(void) if (prev && version == FLASH_HOOK_VERSION && size == sizeof(*prev)) entire_flash_locked = prev->entire_flash_locked; - 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_physical_protect_ro_at_boot(1); - 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. - */ - flash_protect_ro_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; - } + return 1; } - if (need_reset) - system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); - - return EC_SUCCESS; + return 0; } /*****************************************************************************/ diff --git a/chip/stm32/flash-stm32l.c b/chip/stm32/flash-stm32l.c index 62d20ca56e..90ed1a9d55 100644 --- a/chip/stm32/flash-stm32l.c +++ b/chip/stm32/flash-stm32l.c @@ -316,18 +316,21 @@ int flash_physical_get_protect(int block) return STM32_FLASH_WRPR & (1 << block); } -int flash_physical_protect_ro_at_boot(int enable) +int flash_physical_protect_at_boot(enum flash_wp_range range) { uint32_t prot; uint32_t mask = ((1 << (RO_BANK_COUNT + PSTATE_BANK_COUNT)) - 1) << RO_BANK_OFFSET; int rv; + if (range == FLASH_WP_ALL) + return EC_ERROR_UNIMPLEMENTED; + /* Read the current protection status */ prot = read_optb_wrp(); /* Set/clear bits */ - if (enable) + if (range == FLASH_WP_RO) prot |= mask; else prot &= ~mask; diff --git a/common/flash.c b/common/flash.c index b19096b9e3..bd2c191ee7 100644 --- a/common/flash.c +++ b/common/flash.c @@ -188,7 +188,7 @@ int flash_protect_ro_at_boot(int enable) * This assumes PSTATE immediately follows RO, which it does on * all STM32 platforms (which are the only ones with this config). */ - flash_physical_protect_ro_at_boot(new_flags); + flash_physical_protect_at_boot(new_flags ? FLASH_WP_RO : FLASH_WP_NONE); #endif return EC_SUCCESS; diff --git a/include/flash.h b/include/flash.h index 2079032a0a..dff1be7948 100644 --- a/include/flash.h +++ b/include/flash.h @@ -28,6 +28,13 @@ #define PSTATE_BANK (PSTATE_OFFSET / CONFIG_FLASH_BANK_SIZE) #define PSTATE_BANK_COUNT (PSTATE_SIZE / CONFIG_FLASH_BANK_SIZE) +/* Range of write protection */ +enum flash_wp_range { + FLASH_WP_NONE = 0, + FLASH_WP_RO, + FLASH_WP_ALL, +}; + /*****************************************************************************/ /* Low-level methods, for use by flash_common. */ @@ -70,12 +77,12 @@ int flash_physical_get_protect(int bank); uint32_t flash_physical_get_protect_flags(void); /** - * Enable/disable protecting RO firmware and pstate at boot. + * Enable/disable protecting firmware/pstate at boot. * - * @param enable Enable (non-zero) or disable (zero) protection + * @param range The range to protect * @return non-zero if error. */ -int flash_physical_protect_ro_at_boot(int enable); +int flash_physical_protect_at_boot(enum flash_wp_range range); /** * Protect flash now. @@ -96,6 +103,13 @@ int flash_physical_protect_now(int all); */ int flash_physical_force_reload(void); +/** + * Restore flash physical layer state after sysjump. + * + * @return non-zero if restored. + */ +int flash_physical_restore_state(void); + /*****************************************************************************/ /* Low-level common code for use by flash modules. */ |