summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHLin <CHLIN56@nuvoton.com>2019-09-26 16:24:38 +0800
committerCommit Bot <commit-bot@chromium.org>2019-11-22 12:14:41 +0000
commit3ef7e92840d8d80af097c4adf6b8b4c61e241c19 (patch)
tree62f98c494c6a7208a62c1a9d9a457b03650ed2d9
parentc1c35bbd9ee4869f3b5e0bb95847c57a3b3ededa (diff)
downloadchrome-ec-3ef7e92840d8d80af097c4adf6b8b4c61e241c19.tar.gz
npcx7: i2c: enable FIFO mode to transmit and receive data
In npcx7, all I2C modules have separate 32-byte transmit FIFO and 32-byte receive FIFO buffers. In this CL, we add the FIFO mode support to the I2C driver. This will help to reduce the firmware overhead (i.e. the occurrence of I2C interrupt) during long I2C transactions by allowing the EC to write/read more than one byte of data at one time to I2C module and hence improve the I2C performance. The FIFO mode is enabled by default on all npcx7 series chips. BUG=none BRANCH=none TEST=No error for "make buildall" TEST=Connect npcx7 EVB to the I2C slave emulator, do stress test: 1. iterate ~2000 times of single i2c_xfer_unlocked API call. i.e. i2c_xfer_unlocked(.., I2C_XFER_SINGLE) 2. iterate ~2000 times of multiple i2c_xfer_unlocked API calls: i.e. i2c_xfer_unlocked(.., I2C_XFER_START) i2c_xfer_unlocked(.., 0) . . i2c_xfer_unlocked(.., I2C_XFER_STOP) 3. Issue 6 I2C transactions by 6 tasks at the same time. iterates ~2000 times. TEST=with this CL; build and upload an image (with/without FIFO mode enabled.) to yorp; no symptom occurs. Change-Id: I387e8ef6e619acef670273f08ab4150e3d2b75f2 Signed-off-by: CHLin <CHLIN56@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1827137 Tested-by: CH Lin <chlin56@nuvoton.com> Reviewed-by: Jett Rink <jettrink@chromium.org> Commit-Queue: CH Lin <chlin56@nuvoton.com>
-rw-r--r--chip/npcx/config_chip-npcx7.h2
-rw-r--r--chip/npcx/i2c.c427
-rw-r--r--chip/npcx/registers.h29
3 files changed, 378 insertions, 80 deletions
diff --git a/chip/npcx/config_chip-npcx7.h b/chip/npcx/config_chip-npcx7.h
index fe88bc3016..27d7920a3a 100644
--- a/chip/npcx/config_chip-npcx7.h
+++ b/chip/npcx/config_chip-npcx7.h
@@ -55,6 +55,8 @@
#define I2C_PORT_COUNT 11
#endif
+#define NPCX_I2C_FIFO_SUPPORT
+
/* Use SHI module version 2 supported by npcx7 family */
#define NPCX_SHI_V2
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c
index 81e69a3d64..bae14aa101 100644
--- a/chip/npcx/i2c.c
+++ b/chip/npcx/i2c.c
@@ -21,9 +21,11 @@
#if !(DEBUG_I2C)
#define CPUTS(...)
#define CPRINTS(...)
+#define CPRINTF(...)
#else
#define CPUTS(outstr) cputs(CC_I2C, outstr)
#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
#endif
/* Timeout for device should be available after reset (SMBus spec. unit:ms) */
@@ -35,13 +37,40 @@
*/
#define I2C_MIN_TIMEOUT 25
+/*
+ * I2C module that supports FIFO mode has 32 bytes Tx FIFO and
+ * 32 bytes Rx FIFO.
+ */
+#define NPCX_I2C_FIFO_MAX_SIZE 32
+
/* Macro 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)
#define I2C_NACK(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_ACK)
+/* I2C moudule automatically stall bus after sending slave address */
#define I2C_STALL(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_STASTRE)
#define I2C_WRITE_BYTE(ctrl, data) (NPCX_SMBSDA(ctrl) = data)
#define I2C_READ_BYTE(ctrl, data) (data = NPCX_SMBSDA(ctrl))
+#define I2C_TX_FIFO_OCCUPIED(ctrl) (NPCX_SMBTXF_STS(ctrl) & 0x3F)
+#define I2C_TX_FIFO_AVAILABLE(ctrl) \
+ (NPCX_I2C_FIFO_MAX_SIZE - I2C_TX_FIFO_OCCUPIED(ctrl))
+
+#define I2C_RX_FIFO_OCCUPIED(ctrl) (NPCX_SMBRXF_STS(ctrl) & 0x3F)
+#define I2C_RX_FIFO_AVAILABLE(ctrl) \
+ (NPCX_I2C_FIFO_MAX_SIZE - I2C_RX_FIFO_OCCUPIED(ctrl))
+/* Drive the SCL signal to low */
+#define I2C_SCL_STALL(ctrl) \
+ (NPCX_SMBCTL3(ctrl) = \
+ (NPCX_SMBCTL3(ctrl) & ~BIT(NPCX_SMBCTL3_SCL_LVL)) | \
+ BIT(NPCX_SMBCTL3_SDA_LVL))
+/*
+ * Release the SCL signal to be pulled up to high level.
+ * Note: The SCL might be still driven low either by I2C module or external
+ * devices connected to ths bus.
+ */
+#define I2C_SCL_FREE(ctrl) \
+ (NPCX_SMBCTL3(ctrl) |= BIT(NPCX_SMBCTL3_SCL_LVL) | \
+ BIT(NPCX_SMBCTL3_SDA_LVL))
/* Error values that functions can return */
enum smb_error {
@@ -91,7 +120,7 @@ struct i2c_status {
uint32_t timeout_us;/* Transaction timeout */
};
/* I2C controller state data array */
-struct i2c_status i2c_stsobjs[I2C_CONTROLLER_COUNT];
+static struct i2c_status i2c_stsobjs[I2C_CONTROLLER_COUNT];
/* I2C timing setting */
struct i2c_timing {
@@ -123,6 +152,10 @@ BUILD_ASSERT(ARRAY_SIZE(i2c_irqs) == I2C_CONTROLLER_COUNT);
static void i2c_init_bus(int controller)
{
+ /* Enable FIFO mode */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ SET_BIT(NPCX_SMBFIF_CTL(controller), NPCX_SMBFIF_CTL_FIFO_EN);
+
/* Enable module - before configuring CTL1 */
SET_BIT(NPCX_SMBCTL2(controller), NPCX_SMBCTL2_ENABLE);
@@ -199,12 +232,47 @@ static int i2c_reset(int controller)
return 1;
}
+static void i2c_select_bank(int controller, int bank)
+{
+ if (bank)
+ SET_BIT(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_BNK_SEL);
+ else
+ CLEAR_BIT(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_BNK_SEL);
+}
+
+static void i2c_stall_bus(int controller, int stall)
+{
+ i2c_select_bank(controller, 0);
+ /*
+ * Enable the writing to SCL_LVL and SDA_LVL bit in
+ * SMBnCTL3 register. Then, firmware can set SCL_LVL to 0 to
+ * stall the bus when needed. Note: this register should be
+ * accessed when bank = 0.
+ */
+ SET_BIT(NPCX_SMBCTL4(controller), NPCX_SMBCTL4_LVL_WE);
+ if (stall)
+ I2C_SCL_STALL(controller);
+ else
+ I2C_SCL_FREE(controller);
+ /*
+ * Disable the writing to SCL_LVL and SDA_LVL bit in
+ * SMBnCTL3 register. It will prevent form changing the level of
+ * SCL/SDA when touching other bits in SMBnCTL3 register.
+ */
+ CLEAR_BIT(NPCX_SMBCTL4(controller), NPCX_SMBCTL4_LVL_WE);
+ i2c_select_bank(controller, 1);
+}
+
static void i2c_recovery(int controller, volatile struct i2c_status *p_status)
{
cprintf(CC_I2C,
"i2c %d recovery! error code is %d, current state is %d\n",
controller, p_status->err_code, p_status->oper_state);
+ /* Make sure the bus is not stalled before exit. */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ i2c_stall_bus(controller, 0);
+
/* Abort data, wait for STOP condition completed. */
i2c_abort_data(controller);
@@ -216,16 +284,52 @@ static void i2c_recovery(int controller, volatile struct i2c_status *p_status)
p_status->oper_state = SMB_IDLE;
}
+/*
+ * This function can be called in either single-byte mode or FIFO mode.
+ * In single-byte mode - it always write 1 byte to SMBSDA register at one time.
+ * In FIFO mode - write as many as available bytes in FIFO at one time.
+ */
+static void i2c_fifo_write_data(int controller)
+{
+ int len, fifo_avail, i;
+
+ volatile struct i2c_status *p_status = i2c_stsobjs + controller;
+
+ len = 1;
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
+ len = p_status->sz_txbuf - p_status->idx_buf;
+ fifo_avail = I2C_TX_FIFO_AVAILABLE(controller);
+ len = MIN(len, fifo_avail);
+ }
+ for (i = 0; i < len; i++) {
+ I2C_WRITE_BYTE(controller,
+ p_status->tx_buf[p_status->idx_buf++]);
+ CPRINTF("%02x ",
+ p_status->tx_buf[p_status->idx_buf - 1]);
+ }
+ CPRINTF("\n");
+}
+
enum smb_error i2c_master_transaction(int controller)
{
/* Set i2c mode to object */
int events = 0;
volatile struct i2c_status *p_status = i2c_stsobjs + controller;
+ /* Switch to bank 1 to access I2C FIO registers */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ i2c_select_bank(controller, 1);
+
/* Assign current SMB status of controller */
if (p_status->oper_state == SMB_IDLE) {
/* New transaction */
p_status->oper_state = SMB_MASTER_START;
+ /* Clear FIFO and status bit */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
+ NPCX_SMBFIF_CTS(controller) =
+ BIT(NPCX_SMBFIF_CTS_RXF_TXE) |
+ BIT(NPCX_SMBFIF_CTS_CLR_FIFO);
+ }
} else if (p_status->oper_state == SMB_WRITE_SUSPEND) {
if (p_status->sz_txbuf == 0) {
/* Read bytes from next transaction */
@@ -234,34 +338,75 @@ enum smb_error i2c_master_transaction(int controller)
} else {
/* Continue to write the other bytes */
p_status->oper_state = SMB_WRITE_OPER;
- I2C_WRITE_BYTE(controller,
- p_status->tx_buf[p_status->idx_buf++]);
- CPRINTS("-W(%02x)",
- p_status->tx_buf[p_status->idx_buf-1]);
+ CPRINTS("-W");
+ /*
+ * This function can be called in either single-byte
+ * mode or FIFO mode.
+ */
+ i2c_fifo_write_data(controller);
}
} else if (p_status->oper_state == SMB_READ_SUSPEND) {
- /*
- * Do dummy read if read length is 1 and I2C_XFER_STOP is set
- * simultaneously.
- */
- if (p_status->sz_rxbuf == 1 &&
- (p_status->flags & I2C_XFER_STOP)) {
+ if (!IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
/*
- * Since SCL is released after reading last byte from
- * previous transaction, adding a dummy byte for next
- * transaction which let ec sets NACK bit in time is
- * necessary. Or i2c master cannot generate STOP
- * when the last byte is ACK during receiving.
+ * Do dummy read if read length is 1 and I2C_XFER_STOP
+ * is set simultaneously.
*/
- p_status->sz_rxbuf++;
- p_status->oper_state = SMB_DUMMY_READ_OPER;
- } else
- /* Need to read the other bytes from next transaction */
- p_status->oper_state = SMB_READ_OPER;
+ if (p_status->sz_rxbuf == 1 &&
+ (p_status->flags & I2C_XFER_STOP)) {
+ /*
+ * Since SCL is released after reading last
+ * byte from previous transaction, adding a
+ * dummy byte for next transaction which let
+ * ec sets NACK bit in time is necessary.
+ * Or i2c master cannot generate STOP
+ * when the last byte is ACK during receiving.
+ */
+ p_status->sz_rxbuf++;
+ p_status->oper_state = SMB_DUMMY_READ_OPER;
+ } else
+ /*
+ * Need to read the other bytes from
+ * next transaction
+ */
+ p_status->oper_state = SMB_READ_OPER;
+ }
} else
cprintf(CC_I2C, "Unexpected i2c state machine! %d\n",
p_status->oper_state);
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
+ if (p_status->sz_rxbuf > 0) {
+ if (p_status->sz_rxbuf > NPCX_I2C_FIFO_MAX_SIZE) {
+ /* Set RX threshold = FIFO_MAX_SIZE */
+ SET_FIELD(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_RX_THR,
+ NPCX_I2C_FIFO_MAX_SIZE);
+ } else {
+ /*
+ * set RX threshold = remaining data bytes
+ * (it should be <= FIFO_MAX_SIZE)
+ */
+ SET_FIELD(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_RX_THR,
+ p_status->sz_rxbuf);
+ /*
+ * Set LAST bit generate the NACK at the
+ * last byte of the data group in FIFO
+ */
+ if (p_status->flags & I2C_XFER_STOP) {
+ SET_BIT(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_LAST);
+ }
+ }
+
+ /* Free the stalled SCL signal */
+ if (p_status->oper_state == SMB_READ_SUSPEND) {
+ p_status->oper_state = SMB_READ_OPER;
+ i2c_stall_bus(controller, 0);
+ }
+ }
+ }
+
/* Generate a START condition */
if (p_status->oper_state == SMB_MASTER_START ||
p_status->oper_state == SMB_REPEAT_START) {
@@ -280,6 +425,13 @@ enum smb_error i2c_master_transaction(int controller)
task_disable_irq(i2c_irqs[controller]);
/*
+ * Accessing FIFO register is only needed during transaction.
+ * Switch back to bank 0 at the end of transaction
+ */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ i2c_select_bank(controller, 0);
+
+ /*
* If Stall-After-Start mode is still enabled since NACK or BUS error
* occurs, disable it.
*/
@@ -318,6 +470,11 @@ void i2c_done(int controller)
/* Issue a STOP condition on the bus */
I2C_STOP(controller);
CPUTS("-SP");
+ /* Clear RXF_TXE bit (RX FIFO full/TX FIFO empty) */
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ NPCX_SMBFIF_CTS(controller) =
+ BIT(NPCX_SMBFIF_CTS_RXF_TXE);
+
/* Clear SDAST by writing dummy byte */
I2C_WRITE_BYTE(controller, 0xFF);
}
@@ -341,10 +498,167 @@ void i2c_done(int controller)
CPUTS("-END");
}
+static void i2c_handle_receive(int controller)
+{
+ uint8_t data;
+ volatile struct i2c_status *p_status = i2c_stsobjs + controller;
+
+ /* last byte is about to be read - end of transaction */
+ if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) {
+ /* need to STOP or not */
+ if (p_status->flags & I2C_XFER_STOP) {
+ /* Stop should set before reading last byte */
+ I2C_STOP(controller);
+ CPUTS("-SP");
+ } else {
+ /*
+ * Disable interrupt before i2c master read SDA
+ * reg (stall SCL) and forbid SDAST generate
+ * interrupt until starting other transactions
+ */
+ task_disable_irq(i2c_irqs[controller]);
+ }
+ }
+ /* Check if byte-before-last is about to be read */
+ else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) {
+ /*
+ * Set nack before reading byte-before-last,
+ * so that nack will be generated after receive
+ * of last byte
+ */
+ if (p_status->flags & I2C_XFER_STOP) {
+ I2C_NACK(controller);
+ CPUTS("-GNA");
+ }
+ }
+
+ /* Read data for SMBSDA */
+ I2C_READ_BYTE(controller, data);
+ CPRINTS("-R(%02x)", data);
+
+ /* Read to buf. Skip last byte if meet SMB_DUMMY_READ_OPER */
+ if (p_status->oper_state == SMB_DUMMY_READ_OPER &&
+ p_status->idx_buf == (p_status->sz_rxbuf - 1))
+ p_status->idx_buf++;
+ else
+ p_status->rx_buf[p_status->idx_buf++] = data;
+
+ /* last byte is read - end of transaction */
+ if (p_status->idx_buf == p_status->sz_rxbuf) {
+ /* Set current status */
+ p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
+ ? SMB_IDLE : SMB_READ_SUSPEND;
+ /* Set error code */
+ p_status->err_code = SMB_OK;
+ /* Notify upper layer of missing data */
+ task_set_event(p_status->task_waiting,
+ TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-END");
+ }
+}
+
+static void i2c_fifo_read_data(int controller, uint8_t bytes_in_fifo)
+{
+ volatile struct i2c_status *p_status = i2c_stsobjs + controller;
+
+ while (bytes_in_fifo--) {
+ uint8_t data;
+
+ data = NPCX_SMBSDA(controller);
+ p_status->rx_buf[p_status->idx_buf++] = data;
+ CPRINTF("%02x ", data);
+ }
+ CPRINTF("\n");
+}
+
+static void i2c_fifo_handle_receive(int controller)
+{
+ uint8_t bytes_in_fifo, remaining_bytes;
+
+ volatile struct i2c_status *p_status = i2c_stsobjs + controller;
+
+ /*
+ * Clear RX_THST bit (RX-FIFO Threshold Status).
+ * It is set when RX_BYTES = RX_THR after being RX_BYTES < RX_THR
+ */
+ SET_BIT(NPCX_SMBRXF_STS(controller), NPCX_SMBRXF_STS_RX_THST);
+ SET_BIT(NPCX_SMBFIF_CTS(controller), NPCX_SMBFIF_CTS_RXF_TXE);
+
+ bytes_in_fifo = I2C_RX_FIFO_OCCUPIED(controller);
+ remaining_bytes = p_status->sz_rxbuf - p_status->idx_buf;
+ if (remaining_bytes - bytes_in_fifo <= 0) {
+ /*
+ * Last byte is about to be read - end of transaction.
+ * Stop should be set before reading last byte.
+ */
+ if (p_status->flags & I2C_XFER_STOP) {
+ I2C_STOP(controller);
+ CPUTS("-FSP");
+ } else {
+ task_disable_irq(i2c_irqs[controller]);
+ /*
+ * The I2C bus will be freed from stalled and continue
+ * to recevie data when reading data from FIFO.
+ * Pull SCL signal down to stall the bus manually.
+ * SCL signal will be freed when it gets a new I2C
+ * transaction call from common layer.
+ */
+ i2c_stall_bus(controller, 1);
+ }
+
+ CPRINTS("-LFR");
+ i2c_fifo_read_data(controller, remaining_bytes);
+ } else {
+ CPRINTS("-FR");
+ /*
+ * The I2C bus will be freed from stalled and continue to
+ * recevie data when reading data from FIFO.
+ * This may caue driver cannot set the new Rx threshold in time.
+ * Manually stall SCL signal until the new Rx threshold is set.
+ */
+ i2c_stall_bus(controller, 1);
+ i2c_fifo_read_data(controller, bytes_in_fifo);
+ remaining_bytes = p_status->sz_rxbuf - p_status->idx_buf;
+ if (remaining_bytes > 0) {
+ if (remaining_bytes > NPCX_I2C_FIFO_MAX_SIZE) {
+ SET_FIELD(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_RX_THR,
+ NPCX_I2C_FIFO_MAX_SIZE);
+ } else {
+ SET_FIELD(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_RX_THR,
+ remaining_bytes);
+ if (p_status->flags & I2C_XFER_STOP) {
+ SET_BIT(NPCX_SMBRXF_CTL(controller),
+ NPCX_SMBRXF_CTL_LAST);
+ CPRINTS("-FGNA");
+ }
+ }
+
+ }
+ i2c_stall_bus(controller, 0);
+
+ }
+ /* last byte is read - end of transaction */
+ if (p_status->idx_buf == p_status->sz_rxbuf) {
+ /* Set current status */
+ p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
+ ? SMB_IDLE : SMB_READ_SUSPEND;
+ /* Set error code */
+ p_status->err_code = SMB_OK;
+ /* Notify upper layer of missing data */
+ task_set_event(p_status->task_waiting,
+ TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-END");
+ }
+
+}
+
static void i2c_handle_sda_irq(int controller)
{
volatile struct i2c_status *p_status = i2c_stsobjs + controller;
uint8_t addr_8bit = I2C_GET_ADDR(p_status->slave_addr_flags) << 1;
+
/* 1 Issue Start is successful ie. write address byte */
if (p_status->oper_state == SMB_MASTER_START
|| p_status->oper_state == SMB_REPEAT_START) {
@@ -361,12 +675,12 @@ static void i2c_handle_sda_irq(int controller)
/* Write the address to the bus R bit*/
I2C_WRITE_BYTE(controller, (addr_8bit | 0x1));
- CPRINTS("-ARR-0x%02x", addr);
+ CPRINTS("-ARR-0x%02x", addr_8bit);
} else {/* Transmit mode */
p_status->oper_state = SMB_WRITE_OPER;
/* Write the address to the bus W bit*/
I2C_WRITE_BYTE(controller, addr_8bit);
- CPRINTS("-ARW-0x%02x", addr);
+ CPRINTS("-ARW-0x%02x", addr_8bit);
}
/* Completed handling START condition */
return;
@@ -411,68 +725,21 @@ static void i2c_handle_sda_irq(int controller)
}
/* write next byte (not last byte and not slave address */
else {
- I2C_WRITE_BYTE(controller,
- p_status->tx_buf[p_status->idx_buf++]);
- CPRINTS("-W(%02x)",
- p_status->tx_buf[p_status->idx_buf-1]);
+ /*
+ * This function can be called in either single-byte
+ * mode or FIFO mode.
+ */
+ CPRINTS("-W");
+ i2c_fifo_write_data(controller);
}
}
/* 3 Handle master read operation (read or after a write operation) */
else if (p_status->oper_state == SMB_READ_OPER ||
p_status->oper_state == SMB_DUMMY_READ_OPER) {
- uint8_t data;
- /* last byte is about to be read - end of transaction */
- if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) {
- /* need to STOP or not */
- if (p_status->flags & I2C_XFER_STOP) {
- /* Stop should set before reading last byte */
- I2C_STOP(controller);
- CPUTS("-SP");
- } else {
- /*
- * Disable interrupt before i2c master read SDA
- * reg (stall SCL) and forbid SDAST generate
- * interrupt until starting other transactions
- */
- task_disable_irq(i2c_irqs[controller]);
- }
- }
- /* Check if byte-before-last is about to be read */
- else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) {
- /*
- * Set nack before reading byte-before-last,
- * so that nack will be generated after receive
- * of last byte
- */
- if (p_status->flags & I2C_XFER_STOP) {
- I2C_NACK(controller);
- CPUTS("-GNA");
- }
- }
-
- /* Read data for SMBSDA */
- I2C_READ_BYTE(controller, data);
- CPRINTS("-R(%02x)", data);
-
- /* Read to buf. Skip last byte if meet SMB_DUMMY_READ_OPER */
- if (p_status->oper_state == SMB_DUMMY_READ_OPER &&
- p_status->idx_buf == (p_status->sz_rxbuf - 1))
- p_status->idx_buf++;
+ if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
+ i2c_fifo_handle_receive(controller);
else
- p_status->rx_buf[p_status->idx_buf++] = data;
-
- /* last byte is read - end of transaction */
- if (p_status->idx_buf == p_status->sz_rxbuf) {
- /* Set current status */
- p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
- ? SMB_IDLE : SMB_READ_SUSPEND;
- /* Set error code */
- p_status->err_code = SMB_OK;
- /* Notify upper layer of missing data */
- task_set_event(p_status->task_waiting,
- TASK_EVENT_I2C_IDLE, 0);
- CPUTS("-END");
- }
+ i2c_handle_receive(controller);
}
}
@@ -774,7 +1041,7 @@ static void i2c_freq_changed(void)
int i2c_timing_used;
/* use Fast Mode */
- SET_BIT(NPCX_SMBCTL3(ctrl) , NPCX_SMBCTL3_400K);
+ SET_BIT(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_400K);
/*
* Set SCLH(L)T and hold-time directly for best i2c
* timing condition for all source clocks. Please refer
diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h
index 3716b18dfe..b69fc5f806 100644
--- a/chip/npcx/registers.h
+++ b/chip/npcx/registers.h
@@ -776,6 +776,7 @@ enum {
#define NPCX_SMBTMR_EN(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00B)
#define NPCX_SMBADDR2(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00C)
#define NPCX_SMBCTL3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00E)
+/* SMB Registers in bank 0 */
#define NPCX_SMBADDR3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x010)
#define NPCX_SMBADDR7(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x011)
#define NPCX_SMBADDR4(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x012)
@@ -786,7 +787,20 @@ enum {
#define NPCX_SMBCST3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x019)
#define NPCX_SMBCTL4(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01A)
#define NPCX_SMBSCLLT(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01C)
+#define NPCX_SMBFIF_CTL(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01D)
#define NPCX_SMBSCLHT(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01E)
+/* SMB Registers in bank 1 */
+#define NPCX_SMBFIF_CTS(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x010)
+#define NPCX_SMBTXF_CTL(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x012)
+#define NPCX_SMB_T_OUT(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x014)
+/*
+ * These two registers are the same as in bank 0
+ * #define NPCX_SMBCST2(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x018)
+ * #define NPCX_SMBCST3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x019)
+ */
+#define NPCX_SMBTXF_STS(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01A)
+#define NPCX_SMBRXF_STS(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01C)
+#define NPCX_SMBRXF_CTL(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01E)
/* SMBus register fields */
#define NPCX_SMBST_XMIT 0
@@ -829,9 +843,11 @@ enum {
#define NPCX_SMBCTL3_SCLFRQ2_FIELD FIELD(0, 2)
#define NPCX_SMBCTL3_IDL_START 3
#define NPCX_SMBCTL3_400K 4
+#define NPCX_SMBCTL3_BNK_SEL 5
#define NPCX_SMBCTL3_SDA_LVL 6
#define NPCX_SMBCTL3_SCL_LVL 7
#define NPCX_SMBCTL4_HLDT_FIELD FIELD(0, 6)
+#define NPCX_SMBCTL4_LVL_WE 7
#define NPCX_SMBADDR1_SAEN 7
#define NPCX_SMBADDR2_SAEN 7
#define NPCX_SMBADDR3_SAEN 7
@@ -847,6 +863,19 @@ enum {
#define NPCX_SMBSEL_SMB5SEL 5
#define NPCX_SMBSEL_SMB6SEL 6
#endif
+#define NPCX_SMBFIF_CTS_RXF_TXE 1
+#define NPCX_SMBFIF_CTS_CLR_FIFO 6
+
+#define NPCX_SMBFIF_CTL_FIFO_EN 4
+
+#define NPCX_SMBRXF_STS_RX_THST 6
+
+/* RX FIFO threshold */
+#define NPCX_SMBRXF_CTL_RX_THR FIELD(0, 6)
+/*
+ * In master receiving mode, last byte in FIFO should send ACK or NACK
+ */
+#define NPCX_SMBRXF_CTL_LAST 7
/*
* SMB enumeration
* I2C port definitions.