summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--chip/stm32/build.mk3
-rw-r--r--chip/stm32/flash-f.c448
-rw-r--r--chip/stm32/flash-stm32f.c430
-rw-r--r--chip/stm32/flash-stm32l.c7
-rw-r--r--common/flash.c2
-rw-r--r--include/flash.h20
7 files changed, 486 insertions, 431 deletions
diff --git a/Makefile b/Makefile
index 92440e4c36..321823a5d5 100644
--- a/Makefile
+++ b/Makefile
@@ -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. */