diff --git a/src/device/Kconfig b/src/device/Kconfig index 7f20d709ad..388972ccf4 100644 --- a/src/device/Kconfig +++ b/src/device/Kconfig @@ -906,6 +906,14 @@ config SOFTWARE_I2C I2C controller is not (yet) available. The platform code needs to provide bindings to manually toggle I2C lines. +config I2C_TRANSFER_TIMEOUT_US + int "I2C transfer timeout in microseconds" + default 500000 + help + Timeout for a read/write transfers on the I2C bus, that is, the + maximum time a device could stretch clock bits before the transfer + is aborted and an error returned. + config RESOURCE_ALLOCATOR_V3 bool default n diff --git a/src/drivers/i2c/designware/dw_i2c.c b/src/drivers/i2c/designware/dw_i2c.c index 2cc236e81b..56f3f27c1d 100644 --- a/src/drivers/i2c/designware/dw_i2c.c +++ b/src/drivers/i2c/designware/dw_i2c.c @@ -13,6 +13,8 @@ /* Use a ~10ms timeout for various operations */ #define DW_I2C_TIMEOUT_US 10000 +/* Timeout for waiting for FIFO to flush */ +#define DW_I2C_FLUSH_TIMEOUT_US 160000 /* High and low times in different speed modes (in ns) */ enum { @@ -290,7 +292,7 @@ static enum cb_err dw_i2c_wait_for_bus_idle(struct dw_i2c_regs *regs) struct stopwatch sw; /* Start timeout for up to 16 bytes in FIFO */ - stopwatch_init_usecs_expire(&sw, 16 * DW_I2C_TIMEOUT_US); + stopwatch_init_usecs_expire(&sw, DW_I2C_FLUSH_TIMEOUT_US); while (!stopwatch_expired(&sw)) { uint32_t status = read32(®s->status); @@ -316,7 +318,7 @@ static enum cb_err dw_i2c_transfer_byte(struct dw_i2c_regs *regs, struct stopwatch sw; uint32_t cmd = CMD_DATA_CMD; /* Read op */ - stopwatch_init_usecs_expire(&sw, DW_I2C_TIMEOUT_US); + stopwatch_init_usecs_expire(&sw, CONFIG_I2C_TRANSFER_TIMEOUT_US); if (!(segment->flags & I2C_M_RD)) { /* Write op only: Wait for FIFO not full */ @@ -409,7 +411,7 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm } /* Wait for interrupt status to indicate transfer is complete */ - stopwatch_init_usecs_expire(&sw, DW_I2C_TIMEOUT_US); + stopwatch_init_usecs_expire(&sw, CONFIG_I2C_TRANSFER_TIMEOUT_US); while (!(read32(®s->raw_intr_stat) & INTR_STAT_STOP_DET)) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "I2C stop bit not received\n"); @@ -436,7 +438,7 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm } /* Flush the RX FIFO in case it is not empty */ - stopwatch_init_usecs_expire(&sw, 16 * DW_I2C_TIMEOUT_US); + stopwatch_init_usecs_expire(&sw, DW_I2C_FLUSH_TIMEOUT_US); while (read32(®s->status) & STATUS_RX_FIFO_NOT_EMPTY) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "I2C timeout flushing RX FIFO\n"); diff --git a/src/soc/cavium/cn81xx/twsi.c b/src/soc/cavium/cn81xx/twsi.c index bb91b88ebb..b1c1e66fae 100644 --- a/src/soc/cavium/cn81xx/twsi.c +++ b/src/soc/cavium/cn81xx/twsi.c @@ -12,6 +12,7 @@ #include #include #include +#include #define TWSI_THP 24 @@ -348,17 +349,15 @@ static u8 twsi_read_status(void *baseaddr) * * @return 0 for success, 1 if timeout */ -static int twsi_wait(void *baseaddr) +static int twsi_wait(void *baseaddr, struct stopwatch *timeout) { - unsigned long timeout = 500000; u8 twsi_ctl; printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr); do { twsi_ctl = twsi_read_ctl(baseaddr); twsi_ctl &= TWSI_CTL_IFLG; - timeout--; - } while (!twsi_ctl && timeout > 0); + } while (!twsi_ctl && !stopwatch_expired(timeout)); printk(BIOS_SPEW, " return: %u\n", !twsi_ctl); return !twsi_ctl; @@ -438,10 +437,12 @@ static int twsi_start(void *baseaddr) { int result; u8 stat; + struct stopwatch timeout; printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); twsi_write_ctl(baseaddr, TWSI_CTL_STA | TWSI_CTL_ENAB); - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { stat = twsi_read_status(baseaddr); printk(BIOS_SPEW, "%s: result: 0x%x, status: 0x%x\n", __func__, @@ -475,9 +476,11 @@ static int twsi_write_data(void *baseaddr, const u8 slave_addr, union twsx_sw_twsi twsi_sw; unsigned int curr = 0; int result; + struct stopwatch timeout; printk(BIOS_SPEW, "%s(%p, 0x%x, %p, 0x%x)\n", __func__, baseaddr, slave_addr, buffer, length); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); result = twsi_start(baseaddr); if (result) { printk(BIOS_ERR, "%s: Could not start BUS transaction\n", @@ -485,7 +488,7 @@ static int twsi_write_data(void *baseaddr, const u8 slave_addr, return -1; } - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: wait failed\n", __func__); return result; @@ -500,7 +503,7 @@ static int twsi_write_data(void *baseaddr, const u8 slave_addr, twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); printk(BIOS_SPEW, "%s: Waiting\n", __func__); - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: Timed out writing slave address 0x%x\n", __func__, slave_addr); @@ -521,7 +524,7 @@ static int twsi_write_data(void *baseaddr, const u8 slave_addr, twsi_write_sw(baseaddr, twsi_sw); twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: Timed out writing data to 0x%x\n", __func__, slave_addr); @@ -549,16 +552,18 @@ static int twsi_read_data(void *baseaddr, const u8 slave_addr, union twsx_sw_twsi twsi_sw; unsigned int curr = 0; int result; + struct stopwatch timeout; printk(BIOS_SPEW, "%s(%p, 0x%x, %p, %u)\n", __func__, baseaddr, slave_addr, buffer, length); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); result = twsi_start(baseaddr); if (result) { printk(BIOS_ERR, "%s: start failed\n", __func__); return result; } - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: wait failed\n", __func__); return result; @@ -574,7 +579,7 @@ static int twsi_read_data(void *baseaddr, const u8 slave_addr, twsi_write_sw(baseaddr, twsi_sw); twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: waiting for sending addr failed\n", __func__); return result; @@ -590,7 +595,7 @@ static int twsi_read_data(void *baseaddr, const u8 slave_addr, twsi_write_ctl(baseaddr, TWSI_CTL_ENAB | ((curr < length - 1) ? TWSI_CTL_AAK : 0)); - result = twsi_wait(baseaddr); + result = twsi_wait(baseaddr, &timeout); if (result) { printk(BIOS_ERR, "%s: waiting for data failed\n", __func__); diff --git a/src/soc/intel/quark/i2c.c b/src/soc/intel/quark/i2c.c index bb62a7ad01..42ca25dbd9 100644 --- a/src/soc/intel/quark/i2c.c +++ b/src/soc/intel/quark/i2c.c @@ -243,7 +243,7 @@ int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segment, status = regs->ic_clr_tx_abrt; /* Start the timeout */ - stopwatch_init_msecs_expire(&timeout, 1000); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); /* Process each of the segments */ total_bytes = 0; diff --git a/src/soc/mediatek/common/i2c.c b/src/soc/mediatek/common/i2c.c index c47e08e8aa..b4386b96fb 100644 --- a/src/soc/mediatek/common/i2c.c +++ b/src/soc/mediatek/common/i2c.c @@ -239,7 +239,7 @@ static int mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg, /* start transfer transaction */ write32(®s->start, 0x1); - stopwatch_init_msecs_expire(&sw, 100); + stopwatch_init_usecs_expire(&sw, CONFIG_I2C_TRANSFER_TIMEOUT_US); /* polling mode : see if transaction complete */ while (1) { diff --git a/src/soc/qualcomm/common/include/soc/qup_se_handlers_common.h b/src/soc/qualcomm/common/include/soc/qup_se_handlers_common.h index bab7434f0d..a004c7944c 100644 --- a/src/soc/qualcomm/common/include/soc/qup_se_handlers_common.h +++ b/src/soc/qualcomm/common/include/soc/qup_se_handlers_common.h @@ -463,6 +463,6 @@ u32 qup_wait_for_s_irq(unsigned int bus); void qup_m_cancel_and_abort(unsigned int bus); void qup_s_cancel_and_abort(unsigned int bus); int qup_handle_transfer(unsigned int bus, const void *dout, void *din, - int size); + int size, struct stopwatch *timeout); #endif /* __SOC_COMMON_QCOM_QUP_SE_H__ */ diff --git a/src/soc/qualcomm/common/qup_se_handler.c b/src/soc/qualcomm/common/qup_se_handler.c index bb7be37cf0..7dd4f452af 100644 --- a/src/soc/qualcomm/common/qup_se_handler.c +++ b/src/soc/qualcomm/common/qup_se_handler.c @@ -149,15 +149,14 @@ void qup_s_cancel_and_abort(unsigned int bus) } } -int qup_handle_transfer(unsigned int bus, const void *dout, void *din, int size) +int qup_handle_transfer(unsigned int bus, const void *dout, void *din, int size, + struct stopwatch *timeout) { unsigned int m_irq; - struct stopwatch sw; unsigned int rx_rem_bytes = din ? size : 0; unsigned int tx_rem_bytes = dout ? size : 0; struct qup_regs *regs = qup[bus].regs; - stopwatch_init_msecs_expire(&sw, 1000); do { m_irq = qup_wait_for_m_irq(bus); if ((m_irq & M_RX_FIFO_WATERMARK_EN) || @@ -172,7 +171,7 @@ int qup_handle_transfer(unsigned int bus, const void *dout, void *din, int size) break; } write32(®s->geni_m_irq_clear, m_irq); - } while (!stopwatch_expired(&sw)); + } while (!stopwatch_expired(timeout)); if (!(m_irq & M_CMD_DONE_EN) || tx_rem_bytes || rx_rem_bytes) { printk(BIOS_INFO, "%s:Error: Transfer failed\n", __func__); diff --git a/src/soc/qualcomm/common/qupv3_i2c.c b/src/soc/qualcomm/common/qupv3_i2c.c index 606b3bf935..8f0880e35d 100644 --- a/src/soc/qualcomm/common/qupv3_i2c.c +++ b/src/soc/qualcomm/common/qupv3_i2c.c @@ -117,6 +117,7 @@ static int i2c_do_xfer(unsigned int bus, struct i2c_msg segment, unsigned int master_cmd_reg_val = (cmd << M_OPCODE_SHFT); struct qup_regs *regs = qup[bus].regs; void *dout = NULL, *din = NULL; + struct stopwatch timeout; if (!(segment.flags & I2C_M_RD)) { write32(®s->i2c_tx_trans_len, segment.len); @@ -130,7 +131,8 @@ static int i2c_do_xfer(unsigned int bus, struct i2c_msg segment, master_cmd_reg_val |= (prams & M_PARAMS_MSK); write32(®s->geni_m_cmd0, master_cmd_reg_val); - return qup_handle_transfer(bus, dout, din, segment.len); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); + return qup_handle_transfer(bus, dout, din, segment.len, &timeout); } int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, diff --git a/src/soc/qualcomm/common/qupv3_spi.c b/src/soc/qualcomm/common/qupv3_spi.c index c69ecf9eaa..1bb5c75e5e 100644 --- a/src/soc/qualcomm/common/qupv3_spi.c +++ b/src/soc/qualcomm/common/qupv3_spi.c @@ -83,6 +83,7 @@ int qup_spi_xfer(const struct spi_slave *slave, const void *dout, int size; unsigned int se_bus = slave->bus; struct qup_regs *regs = qup[se_bus].regs; + struct stopwatch timeout; if ((bytes_in == 0) && (bytes_out == 0)) return 0; @@ -114,7 +115,8 @@ int qup_spi_xfer(const struct spi_slave *slave, const void *dout, qup_setup_m_cmd(se_bus, m_cmd, m_param); - if (qup_handle_transfer(se_bus, dout, din, size)) + stopwatch_init_msecs_expire(&timeout, 1000); + if (qup_handle_transfer(se_bus, dout, din, size, &timeout)) return -1; qup_spi_xfer(slave, dout + size, MAX((int)bytes_out - size, 0), diff --git a/src/soc/qualcomm/ipq40xx/qup.c b/src/soc/qualcomm/ipq40xx/qup.c index 76f079744c..88e9169ec7 100644 --- a/src/soc/qualcomm/ipq40xx/qup.c +++ b/src/soc/qualcomm/ipq40xx/qup.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -93,35 +94,33 @@ static qup_return_t qup_reset_master_status(blsp_qup_id_t id) return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status) +static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (!(read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status)) { ret = qup_i2c_master_status(id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status) +static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status) { ret = qup_i2c_master_status(id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; @@ -139,7 +138,8 @@ static inline uint32_t qup_i2c_create_output_tag(int stop, u8 data) return tag; } -static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) +static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; @@ -147,7 +147,7 @@ static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) mdelay(4); /* TPM seems to need this */ - ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY); + ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY, timeout); if (ret) return ret; @@ -168,6 +168,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; uint32_t tag, *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + struct stopwatch timeout; qup_reset_master_status(id); @@ -196,6 +197,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, qup_write32(fifo, tag); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); while (data_len) { tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, @@ -213,7 +215,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, qup_write32(fifo, tag); - ret = qup_i2c_write_fifo_flush(id); + ret = qup_i2c_write_fifo_flush(id, &timeout); if (ret) { printk(QUPDBG "%s: error\n", __func__); @@ -221,7 +223,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, } } - ret = qup_i2c_write_fifo_flush(id); + ret = qup_i2c_write_fifo_flush(id, &timeout); qup_set_state(id, QUP_STATE_RESET); @@ -285,6 +287,7 @@ static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; uint32_t *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + struct stopwatch timeout; qup_reset_master_status(id); @@ -303,13 +306,14 @@ static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)) | ((QUP_I2C_RECV_SEQ | data_len) << 16)); - ret = qup_i2c_write_fifo_flush(id); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); + ret = qup_i2c_write_fifo_flush(id, &timeout); if (ret) { printk(QUPDBG "%s: OUTPUT_FIFO_NOT_EMPTY\n", __func__); return ret; } - ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG); + ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG, &timeout); if (ret) { printk(QUPDBG "%s: INPUT_SERVICE_FLAG\n", __func__); return ret; diff --git a/src/soc/qualcomm/ipq806x/qup.c b/src/soc/qualcomm/ipq806x/qup.c index e2acde3842..e7b45d6eca 100644 --- a/src/soc/qualcomm/ipq806x/qup.c +++ b/src/soc/qualcomm/ipq806x/qup.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -87,35 +88,33 @@ static qup_return_t qup_reset_master_status(gsbi_id_t gsbi_id) return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_for(gsbi_id_t gsbi_id, uint32_t status) +static qup_return_t qup_fifo_wait_for(gsbi_id_t gsbi_id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (!(read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status)) { ret = qup_i2c_master_status(gsbi_id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_while(gsbi_id_t gsbi_id, uint32_t status) +static qup_return_t qup_fifo_wait_while(gsbi_id_t gsbi_id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status) { ret = qup_i2c_master_status(gsbi_id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; @@ -129,6 +128,7 @@ static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, uint8_t *data_ptr = p_tx_obj->p.iic.data; unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; + struct stopwatch timeout; qup_reset_master_status(gsbi_id); qup_set_state(gsbi_id, QUP_STATE_RUN); @@ -136,6 +136,7 @@ static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr))); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); while (data_len) { if (data_len == 1 && stop_seq) { write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), @@ -147,7 +148,8 @@ static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, data_len--; idx++; if (data_len) { - ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_FULL); + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_FULL, + &timeout); if (ret) return ret; } @@ -166,7 +168,7 @@ static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, } } - ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY, &timeout); if (ret) return ret; @@ -202,6 +204,7 @@ static qup_return_t qup_i2c_read_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj) uint8_t *data_ptr = p_tx_obj->p.iic.data; unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; + struct stopwatch timeout; qup_reset_master_status(gsbi_id); qup_set_state(gsbi_id, QUP_STATE_RUN); @@ -212,7 +215,8 @@ static qup_return_t qup_i2c_read_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj) write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), QUP_I2C_RECV_SEQ | data_len); - ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY, &timeout); if (ret) return ret; @@ -221,7 +225,7 @@ static qup_return_t qup_i2c_read_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj) while (data_len) { uint32_t data; - ret = qup_fifo_wait_for(gsbi_id, INPUT_SERVICE_FLAG); + ret = qup_fifo_wait_for(gsbi_id, INPUT_SERVICE_FLAG, &timeout); if (ret) return ret; diff --git a/src/soc/qualcomm/qcs405/qup.c b/src/soc/qualcomm/qcs405/qup.c index 316cd9fed0..e3a4e5e69e 100644 --- a/src/soc/qualcomm/qcs405/qup.c +++ b/src/soc/qualcomm/qcs405/qup.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -129,35 +130,33 @@ static qup_return_t qup_reset_master_status(blsp_qup_id_t id) return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status) +static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (!(read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status)) { ret = qup_i2c_master_status(id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; } -static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status) +static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; - unsigned int count = TIMEOUT_CNT; while (read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status) { ret = qup_i2c_master_status(id); if (ret) return ret; - if (count == 0) + if (stopwatch_expired(timeout)) return QUP_ERR_TIMEOUT; - count--; } return QUP_SUCCESS; @@ -175,7 +174,8 @@ static inline uint32_t qup_i2c_create_output_tag(int stop, u8 data) return tag; } -static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) +static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id, + struct stopwatch *timeout) { qup_return_t ret = QUP_ERR_UNDEFINED; @@ -183,7 +183,7 @@ static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) mdelay(4); /* TPM seems to need this */ - ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY); + ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY, timeout); if (ret) return ret; @@ -204,6 +204,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; uint32_t tag, *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + struct stopwatch timeout; qup_reset_master_status(id); @@ -232,6 +233,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, qup_write32(fifo, tag); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); while (data_len) { tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, @@ -249,7 +251,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, qup_write32(fifo, tag); - ret = qup_i2c_write_fifo_flush(id); + ret = qup_i2c_write_fifo_flush(id, &timeout); if (ret) { printk(QUPDBG "%s: error\n", __func__); @@ -257,7 +259,7 @@ static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, } } - ret = qup_i2c_write_fifo_flush(id); + ret = qup_i2c_write_fifo_flush(id, &timeout); qup_set_state(id, QUP_STATE_RESET); @@ -321,6 +323,7 @@ static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) unsigned int data_len = p_tx_obj->p.iic.data_len; unsigned int idx = 0; uint32_t *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + struct stopwatch timeout; qup_reset_master_status(id); @@ -339,13 +342,14 @@ static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)) | ((QUP_I2C_RECV_SEQ | data_len) << 16)); - ret = qup_i2c_write_fifo_flush(id); + stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); + ret = qup_i2c_write_fifo_flush(id, &timeout); if (ret) { printk(QUPDBG "%s: OUTPUT_FIFO_NOT_EMPTY\n", __func__); return ret; } - ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG); + ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG, &timeout); if (ret) { printk(QUPDBG "%s: INPUT_SERVICE_FLAG\n", __func__); return ret; diff --git a/src/soc/rockchip/common/i2c.c b/src/soc/rockchip/common/i2c.c index dbbfd3e041..a0498a52c7 100644 --- a/src/soc/rockchip/common/i2c.c +++ b/src/soc/rockchip/common/i2c.c @@ -114,7 +114,6 @@ static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) { int res = 0; uint8_t *data = segment.buf; - int timeout = I2C_TIMEOUT_US; unsigned int bytes_remaining = segment.len; unsigned int con = 0; @@ -122,6 +121,7 @@ static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) write32(®_addr->i2c_mrxraddr, 0); con = I2C_MODE_TRX | I2C_EN | I2C_ACT2NAK; while (bytes_remaining) { + int timeout = CONFIG_I2C_TRANSFER_TIMEOUT_US; size_t size = MIN(bytes_remaining, 32); bytes_remaining -= size; if (!bytes_remaining) @@ -132,7 +132,6 @@ static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) write32(®_addr->i2c_con, con); write32(®_addr->i2c_mrxcnt, size); - timeout = I2C_TIMEOUT_US; while (timeout--) { if (read32(®_addr->i2c_ipd) & I2C_NAKRCVI) { write32(®_addr->i2c_mrxcnt, 0); @@ -161,7 +160,6 @@ static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) { int res = 0; uint8_t *data = segment.buf; - int timeout = I2C_TIMEOUT_US; int bytes_remaining = segment.len + 1; /* Prepend one byte for the slave address to the transfer. */ @@ -169,6 +167,7 @@ static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) int prefsz = 1; while (bytes_remaining) { + int timeout = CONFIG_I2C_TRANSFER_TIMEOUT_US; size_t size = MIN(bytes_remaining, 32); buffer_to_fifo32_prefix(data, prefix, prefsz, size, ®_addr->txdata, 4, 4); @@ -180,7 +179,6 @@ static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment) I2C_EN | I2C_MODE_TX | I2C_ACT2NAK); write32(®_addr->i2c_mtxcnt, size); - timeout = I2C_TIMEOUT_US; while (timeout--) { if (read32(®_addr->i2c_ipd) & I2C_NAKRCVI) { write32(®_addr->i2c_mtxcnt, 0); diff --git a/src/soc/samsung/exynos5250/i2c.c b/src/soc/samsung/exynos5250/i2c.c index bc5570daad..5ce4c7d814 100644 --- a/src/soc/samsung/exynos5250/i2c.c +++ b/src/soc/samsung/exynos5250/i2c.c @@ -8,6 +8,9 @@ #include #include #include +#include + +#define I2C_TIMEOUT_US (1000 * USECS_PER_MSEC) struct __packed i2c_regs { @@ -119,9 +122,9 @@ static int i2c_got_ack(struct i2c_regs *regs) return !(read8(®s->stat) & I2cStatAck); } -static int i2c_wait_for_idle(struct i2c_regs *regs) +static int i2c_wait_for_idle(struct i2c_regs *regs, int timeout_us) { - int timeout = 1000 * 100; // 1s. + int timeout = DIV_ROUND_UP(timeout_us, 10); while (timeout--) { if (!(read8(®s->stat) & I2cStatBusy)) return 0; @@ -131,9 +134,9 @@ static int i2c_wait_for_idle(struct i2c_regs *regs) return 1; } -static int i2c_wait_for_int(struct i2c_regs *regs) +static int i2c_wait_for_int(struct i2c_regs *regs, int timeout_us) { - int timeout = 1000 * 100; // 1s. + int timeout = DIV_ROUND_UP(timeout_us, 10); while (timeout--) { if (i2c_int_pending(regs)) return 0; @@ -148,7 +151,7 @@ static int i2c_send_stop(struct i2c_regs *regs) uint8_t mode = read8(®s->stat) & (I2cStatModeMask); write8(®s->stat, mode | I2cStatEnable); i2c_clear_int(regs); - return i2c_wait_for_idle(regs); + return i2c_wait_for_idle(regs, I2C_TIMEOUT_US); } static int i2c_send_start(struct i2c_regs *regs, int read, int chip) @@ -158,7 +161,7 @@ static int i2c_send_start(struct i2c_regs *regs, int read, int chip) write8(®s->stat, mode | I2cStatStartStop | I2cStatEnable); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, I2C_TIMEOUT_US)) return 1; if (!i2c_got_ack(regs)) { @@ -180,7 +183,7 @@ static int i2c_xmit_buf(struct i2c_regs *regs, uint8_t *data, int len) write8(®s->ds, data[i]); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US)) return 1; if (!i2c_got_ack(regs)) { @@ -204,7 +207,7 @@ static int i2c_recv_buf(struct i2c_regs *regs, uint8_t *data, int len) i2c_ack_disable(regs); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US)) return 1; data[i] = read8(®s->ds); @@ -220,7 +223,7 @@ int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, struct i2c_regs *regs = i2c->regs; int res = 0; - if (!regs || i2c_wait_for_idle(regs)) + if (!regs || i2c_wait_for_idle(regs, I2C_TIMEOUT_US)) return 1; write8(®s->stat, I2cStatMasterXmit | I2cStatEnable); diff --git a/src/soc/samsung/exynos5420/i2c.c b/src/soc/samsung/exynos5420/i2c.c index ab17d52c44..49505a0782 100644 --- a/src/soc/samsung/exynos5420/i2c.c +++ b/src/soc/samsung/exynos5420/i2c.c @@ -11,6 +11,8 @@ #include #include +#define I2C_TIMEOUT_US (1000 * USECS_PER_MSEC) + struct __packed i2c_regs { uint8_t con; @@ -508,9 +510,9 @@ static int i2c_got_ack(struct i2c_regs *regs) return !(read8(®s->stat) & I2cStatAck); } -static int i2c_wait_for_idle(struct i2c_regs *regs) +static int i2c_wait_for_idle(struct i2c_regs *regs, int timeout_us) { - int timeout = 1000 * 100; // 1s. + int timeout = timeout_us / 10; while (timeout--) { if (!(read8(®s->stat) & I2cStatBusy)) return 0; @@ -520,9 +522,9 @@ static int i2c_wait_for_idle(struct i2c_regs *regs) return 1; } -static int i2c_wait_for_int(struct i2c_regs *regs) +static int i2c_wait_for_int(struct i2c_regs *regs, int timeout_us) { - int timeout = 1000 * 100; // 1s. + int timeout = timeout_us / 10; while (timeout--) { if (i2c_int_pending(regs)) return 0; @@ -537,7 +539,7 @@ static int i2c_send_stop(struct i2c_regs *regs) uint8_t mode = read8(®s->stat) & (I2cStatModeMask); write8(®s->stat, mode | I2cStatEnable); i2c_clear_int(regs); - return i2c_wait_for_idle(regs); + return i2c_wait_for_idle(regs, I2C_TIMEOUT_US); } static int i2c_send_start(struct i2c_regs *regs, int read, int chip) @@ -547,7 +549,7 @@ static int i2c_send_start(struct i2c_regs *regs, int read, int chip) write8(®s->stat, mode | I2cStatStartStop | I2cStatEnable); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, I2C_TIMEOUT_US)) return 1; if (!i2c_got_ack(regs)) { @@ -569,7 +571,7 @@ static int i2c_xmit_buf(struct i2c_regs *regs, uint8_t *data, int len) write8(®s->ds, data[i]); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US)) return 1; if (!i2c_got_ack(regs)) { @@ -593,7 +595,7 @@ static int i2c_recv_buf(struct i2c_regs *regs, uint8_t *data, int len) i2c_ack_disable(regs); i2c_clear_int(regs); - if (i2c_wait_for_int(regs)) + if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US)) return 1; data[i] = read8(®s->ds); @@ -611,7 +613,7 @@ int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count) struct i2c_regs *regs = i2c->regs; int res = 0; - if (!regs || i2c_wait_for_idle(regs)) + if (!regs || i2c_wait_for_idle(regs, I2C_TIMEOUT_US)) return 1; write8(®s->stat, I2cStatMasterXmit | I2cStatEnable);