aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/device/Kconfig8
-rw-r--r--src/drivers/i2c/designware/dw_i2c.c10
-rw-r--r--src/soc/cavium/cn81xx/twsi.c27
-rw-r--r--src/soc/intel/quark/i2c.c2
-rw-r--r--src/soc/mediatek/common/i2c.c2
-rw-r--r--src/soc/qualcomm/common/include/soc/qup_se_handlers_common.h2
-rw-r--r--src/soc/qualcomm/common/qup_se_handler.c7
-rw-r--r--src/soc/qualcomm/common/qupv3_i2c.c4
-rw-r--r--src/soc/qualcomm/common/qupv3_spi.c4
-rw-r--r--src/soc/qualcomm/ipq40xx/qup.c32
-rw-r--r--src/soc/qualcomm/ipq806x/qup.c28
-rw-r--r--src/soc/qualcomm/qcs405/qup.c32
-rw-r--r--src/soc/rockchip/common/i2c.c6
-rw-r--r--src/soc/samsung/exynos5250/i2c.c21
-rw-r--r--src/soc/samsung/exynos5420/i2c.c20
15 files changed, 119 insertions, 86 deletions
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(&regs->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(&regs->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(&regs->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 <delay.h>
#include <device/mmio.h>
#include <soc/addressmap.h>
+#include <timer.h>
#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(&regs->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(&regs->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(&regs->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(&regs->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 <device/mmio.h>
#include <console/console.h>
#include <delay.h>
+#include <timer.h>
#include <soc/iomap.h>
#include <soc/qup.h>
@@ -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 <device/mmio.h>
#include <console/console.h>
#include <delay.h>
+#include <timer.h>
#include <soc/iomap.h>
#include <soc/qup.h>
@@ -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 <device/mmio.h>
#include <console/console.h>
#include <delay.h>
+#include <timer.h>
#include <soc/gpio.h>
#include <soc/iomap.h>
#include <soc/qup.h>
@@ -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(&reg_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(&reg_addr->i2c_con, con);
write32(&reg_addr->i2c_mrxcnt, size);
- timeout = I2C_TIMEOUT_US;
while (timeout--) {
if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {
write32(&reg_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,
&reg_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(&reg_addr->i2c_mtxcnt, size);
- timeout = I2C_TIMEOUT_US;
while (timeout--) {
if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {
write32(&reg_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 <soc/clk.h>
#include <soc/i2c.h>
#include <soc/periph.h>
+#include <timer.h>
+
+#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(&regs->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(&regs->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(&regs->stat) & (I2cStatModeMask);
write8(&regs->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(&regs->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(&regs->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(&regs->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(&regs->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 <soc/pinmux.h>
#include <timer.h>
+#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(&regs->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(&regs->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(&regs->stat) & (I2cStatModeMask);
write8(&regs->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(&regs->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(&regs->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(&regs->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(&regs->stat, I2cStatMasterXmit | I2cStatEnable);