/* 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; }