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