summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2015-08-27 11:10:57 +0800
committerchrome-bot <chrome-bot@chromium.org>2015-09-06 22:12:29 -0700
commite8bdf07a58850cfac026b4ad8409c229446a9243 (patch)
tree6ea66322a08b95dff576107c15b6df4b197e0ec3
parente5e8f84d412dc97d9e33b12fef61b6657627f772 (diff)
downloadchrome-ec-e8bdf07a58850cfac026b4ad8409c229446a9243.tar.gz
nuc: Fixed the bugs for flash and i2c drivers.
Since the length of flash-write function used by host command is not aligned to 256 bytes, we need to split it into several sequences to make sure it won't exceed page buffer size of flash. Add i2c stop condition checking to avoid unnecessary i2c unwedge operations. We found some battery will held scl for a while and master cann't issue stop condition immediately. Modified drivers: 1. flash.c: Add support for sequence programing. 2. i2c.c: Add i2c stop condition checking mechanism. 3. i2c.c: Fixed bug of i2c_is_raw_mode. (wrong bit offset) BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: I4f35a617466ba37bcc4e3aa5324c8950f824a4c2 Signed-off-by: Ian Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/295662 Commit-Ready: Mulin Chao <mlchao@nuvoton.com> Tested-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--chip/npcx/flash.c124
-rw-r--r--chip/npcx/i2c.c60
2 files changed, 126 insertions, 58 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)
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;
}
-int i2c_abort_data(int controller)
+static int i2c_wait_stop_completed(int controller, int timeout)
{
- uint16_t timeout = I2C_ABORT_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)
+{
/* 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;