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 <ryanmcclelland@meta.com>
This commit is contained in:
Ryan McClelland 2023-11-26 10:52:52 -08:00 committed by Henrik Brix Andersen
parent a8d2feef83
commit 1e91453005

View file

@ -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;
}