From 1e91453005d154da2e37b5f0611ddfd268dc28c5 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sun, 26 Nov 2023 10:52:52 -0800 Subject: [PATCH] drivers: i3c: cdns: use deterministic timeout for idle Previously, the idle bit would be read for X amount of times. This could vary alot depend on the CPU speed. Timeout is now to happen from the cycle time. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 71 ++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index cad71e5cae..4f99e8da88 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -375,9 +375,11 @@ #define I3C_MAX_MSGS 10 #define I3C_SIR_DEFAULT_DA 0x7F #define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 -#define I3C_MAX_IDLE_WAIT_RETRIES 5000 #define I3C_PRESCL_REG_SCALE (4) #define I2C_PRESCL_REG_SCALE (5) +#define I3C_WAIT_FOR_IDLE_STATE_US 100 +#define I3C_IDLE_TIMEOUT_CYC \ + (I3C_WAIT_FOR_IDLE_STATE_US * (sys_clock_hw_cycles_per_sec() / USEC_PER_SEC)) /* Target T_LOW period in open-drain mode. */ #define I3C_BUS_TLOW_OD_MIN_NS 200 @@ -613,6 +615,25 @@ static int cdns_i3c_read_rx_fifo(const struct cdns_i3c_config *config, void *buf return 0; } +static inline int cdns_i3c_wait_for_idle(const struct device *dev) +{ + const struct cdns_i3c_config *config = dev->config; + uint32_t start_time = k_cycle_get_32(); + + /** + * Spin waiting for device to go idle. It is unlikely that this will + * actually take any time unless if the last transaction came immediately + * after an error condition. + */ + while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE)) { + if (k_cycle_get_32() - start_time > I3C_IDLE_TIMEOUT_CYC) { + return -EAGAIN; + } + } + + return 0; +} + static void cdns_i3c_set_prescalers(const struct device *dev) { struct cdns_i3c_data *data = dev->data; @@ -995,19 +1016,9 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1383,19 +1394,9 @@ static int cdns_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1676,19 +1677,9 @@ static int cdns_i3c_transfer(const struct device *dev, struct i3c_device_desc *t k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; }