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(); + rv = flash_program_bytes(dest_addr, write_len, data); + if (rv) + return rv; - 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; - - /* 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) diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c index 77788525e4..8b37e8428d 100644 --- a/chip/npcx/i2c.c +++ b/chip/npcx/i2c.c @@ -29,8 +29,11 @@ #define NPCX_I2C_PUBIT(controller, port) \ ((controller*2) + port) -/* Data abort timeout unit:ms*/ -#define I2C_ABORT_TIMEOUT 35 +/* Timeout for device should be available after reset (SMBus spec. unit:ms) */ +#define I2C_MAX_TIMEOUT 35 +/* Timeout for SCL held to low by slave device . (SMBus spec. unit:ms) */ +#define I2C_MIN_TIMEOUT 25 + /* Marco functions of I2C */ #define I2C_START(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_START) #define I2C_STOP(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_STOP) @@ -118,35 +121,49 @@ int i2c_bus_busy(int controller) return IS_BIT_SET(NPCX_SMBCST(controller), NPCX_SMBCST_BB) ? 1 : 0; } +static int i2c_wait_stop_completed(int controller, int timeout) +{ + if (timeout <= 0) + return EC_ERROR_INVAL; + + /* Wait till STOP condition is generated. ie. I2C bus is idle. */ + while (timeout > 0) { + if (!IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STOP)) + break; + if (--timeout > 0) + msleep(1); + } + + if (timeout) + return EC_SUCCESS; + else + return EC_ERROR_TIMEOUT; +} + int i2c_abort_data(int controller) { - uint16_t timeout = I2C_ABORT_TIMEOUT; - /* Clear NEGACK, STASTR and BER bits */ SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER); SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_STASTR); SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_NEGACK); /* Wait till STOP condition is generated */ - while (--timeout) { - if (!IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STOP)) - break; - msleep(1); + if (i2c_wait_stop_completed(controller, I2C_MAX_TIMEOUT) + != EC_SUCCESS) { + cprints(CC_I2C, "Abort i2c %02x fail!", controller); + /* Clear BB (BUS BUSY) bit */ + SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB); + return 0; } /* Clear BB (BUS BUSY) bit */ SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB); - - if (timeout == 0) { - cprints(CC_I2C, "Abort i2c %02x fail!", controller); - return 0; - } else - return 1; + return 1; } void i2c_reset(int controller) { - uint16_t timeout = I2C_ABORT_TIMEOUT; + uint16_t timeout = I2C_MAX_TIMEOUT; /* Disable the SMB module */ CLEAR_BIT(NPCX_SMBCTL2(controller), NPCX_SMBCTL2_ENABLE); @@ -197,7 +214,8 @@ enum smb_error i2c_master_transaction(int controller) /* Wait for transfer complete or timeout */ events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, p_status->timeout_us); - /* Handle timeout */ + + /* Handle bus timeout */ if ((events & TASK_EVENT_I2C_IDLE) == 0) { /* Recovery I2C controller */ i2c_recovery(controller); @@ -212,6 +230,14 @@ enum smb_error i2c_master_transaction(int controller) i2c_recovery(controller); } + /* Wait till STOP condition is generated */ + if (p_status->err_code == SMB_OK && i2c_wait_stop_completed(controller, + I2C_MIN_TIMEOUT) != EC_SUCCESS) { + cprints(CC_I2C, "STOP fail! scl %02x is held by slave device!", + controller); + p_status->err_code = SMB_TIMEOUT_ERROR; + } + return p_status->err_code; } @@ -510,7 +536,7 @@ int i2c_get_line_levels(int port) */ int i2c_is_raw_mode(int port) { - int bit = (port > NPCX_I2C_PORT0_1) ? port * 2 : port; + int bit = (port > NPCX_I2C_PORT0_1) ? ((port - 1) * 2) : port; if (IS_BIT_SET(NPCX_DEVALT(2), bit)) return 0;