diff options
Diffstat (limited to 'chip/npcx/flash.c')
-rw-r--r-- | chip/npcx/flash.c | 124 |
1 files changed, 83 insertions, 41 deletions
diff --git a/chip/npcx/flash.c b/chip/npcx/flash.c index 2780e379de..c97c2b38cc 100644 --- a/chip/npcx/flash.c +++ b/chip/npcx/flash.c @@ -70,16 +70,18 @@ void flash_cs_level(int level) UPDATE_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1, level); } -void flash_wait_ready(void) +static int flash_wait_ready(int timeout) { uint8_t mask = SPI_FLASH_SR1_BUSY; - uint16_t timeout = FLASH_ABORT_TIMEOUT; + + if (timeout <= 0) + return EC_ERROR_INVAL; /* Chip Select down. */ flash_cs_level(0); /* Command for Read status register */ flash_execute_cmd(CMD_READ_STATUS_REG, MASK_CMD_ONLY); - while (--timeout) { + while (timeout > 0) { /* Read status register */ NPCX_UMA_CTS = MASK_RD_1BYTE; while (IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) @@ -87,25 +89,40 @@ void flash_wait_ready(void) /* Busy bit is clear */ if ((NPCX_UMA_DB0 & mask) == 0) break; - - msleep(1); + if (--timeout > 0) + msleep(1); }; /* Wait for Busy clear */ + /* Chip Select high. */ flash_cs_level(1); + + if (timeout == 0) + return EC_ERROR_TIMEOUT; + + return EC_SUCCESS; } int flash_write_enable(void) { uint8_t mask = SPI_FLASH_SR1_WEL; + int rv; + /* Wait for previous operation to complete */ + rv = flash_wait_ready(FLASH_ABORT_TIMEOUT); + if (rv) + return rv; + /* Write enable command */ flash_execute_cmd(CMD_WRITE_EN, MASK_CMD_ONLY); + /* Wait for flash is not busy */ - flash_wait_ready(); + rv = flash_wait_ready(FLASH_ABORT_TIMEOUT); + if (rv) + return rv; if (NPCX_UMA_DB0 & mask) - return 1; + return EC_SUCCESS; else - return 0; + return EC_ERROR_BUSY; } void flash_set_address(uint32_t dest_addr) @@ -375,11 +392,11 @@ void flash_burst_write(unsigned int dest_addr, unsigned int bytes, const char *data) { unsigned int i; - /* Chip Select down. */ + /* Chip Select down */ flash_cs_level(0); - /* Set erase address */ + /* Set write address */ flash_set_address(dest_addr); - /* Start write */ + /* Start programming */ flash_execute_cmd(CMD_FLASH_PROGRAM, MASK_CMD_WR_ADR); for (i = 0; i < bytes; i++) { flash_execute_cmd(*data, MASK_CMD_WR_ONLY); @@ -389,6 +406,38 @@ void flash_burst_write(unsigned int dest_addr, unsigned int bytes, flash_cs_level(1); } +static int flash_program_bytes(uint32_t offset, uint32_t bytes, + const uint8_t const *data) +{ + int write_size; + int rv; + + while (bytes > 0) { + /* Write length can not go beyond the end of the flash page */ + write_size = MIN(bytes, CONFIG_FLASH_WRITE_IDEAL_SIZE - + (offset & (CONFIG_FLASH_WRITE_IDEAL_SIZE - 1))); + + /* Enable write */ + rv = flash_write_enable(); + if (rv) + return rv; + + /* Burst UMA transaction */ + flash_burst_write(offset, write_size, data); + + /* Wait write completed */ + rv = flash_wait_ready(FLASH_ABORT_TIMEOUT); + if (rv) + return rv; + + data += write_size; + offset += write_size; + bytes -= write_size; + } + + return rv; +} + int flash_uma_lock(int enable) { UPDATE_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK, enable); @@ -517,7 +566,8 @@ int flash_physical_is_erased(uint32_t offset, int size) int flash_physical_write(int offset, int size, const char *data) { int dest_addr = offset; - const int sz_page = CONFIG_FLASH_WRITE_IDEAL_SIZE; + int write_len; + int rv; /* Fail if offset, size, and data aren't at least word-aligned */ if ((offset | size @@ -531,45 +581,32 @@ int flash_physical_write(int offset, int size, const char *data) /* Disable tri-state */ TRISTATE_FLASH(0); - /* Write the data per CONFIG_FLASH_WRITE_IDEAL_SIZE bytes */ - for (; size >= sz_page; size -= sz_page) { + while (size > 0) { + /* First write multiples of 256, then (size % 256) last */ + write_len = ((size % CONFIG_FLASH_WRITE_IDEAL_SIZE) == size) ? + size : CONFIG_FLASH_WRITE_IDEAL_SIZE; /* check protection */ - if (flash_check_prot_range(dest_addr, sz_page)) + if (flash_check_prot_range(dest_addr, write_len)) return EC_ERROR_ACCESS_DENIED; - /* Enable write */ - flash_write_enable(); - /* Burst UMA transaction */ - flash_burst_write(dest_addr, sz_page, data); - /* Wait write completed */ - flash_wait_ready(); - - data += sz_page; - dest_addr += sz_page; - } - - /* Handle final partial page, if any */ - if (size != 0) { - /* check protection */ - if (flash_check_prot_range(dest_addr, size)) - return EC_ERROR_ACCESS_DENIED; + rv = flash_program_bytes(dest_addr, write_len, data); + if (rv) + return rv; - /* Enable write */ - flash_write_enable(); - /* Burst UMA transaction */ - flash_burst_write(dest_addr, size, data); - /* Wait write completed */ - flash_wait_ready(); + data += write_len; + dest_addr += write_len; + size -= write_len; } /* Enable tri-state */ TRISTATE_FLASH(1); - return EC_SUCCESS; + return rv; } int flash_physical_erase(int offset, int size) { + int rv; /* check protection */ if (all_protected) return EC_ERROR_ACCESS_DENIED; @@ -597,19 +634,24 @@ int flash_physical_erase(int offset, int size) watchdog_reload(); /* Enable write */ - flash_write_enable(); + rv = flash_write_enable(); + if (rv) + return rv; + /* Set erase address */ flash_set_address(offset); /* Start erase */ flash_execute_cmd(CMD_SECTOR_ERASE, MASK_CMD_ADR); /* Wait erase completed */ - flash_wait_ready(); + rv = flash_wait_ready(FLASH_ABORT_TIMEOUT); + if (rv) + return rv; } /* Enable tri-state */ TRISTATE_FLASH(1); - return EC_SUCCESS; + return rv; } int flash_physical_get_protect(int bank) |