diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 889e2ed5bc83..843861ba62bd 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -5,6 +5,7 @@ * Author: Vitor Soares */ +#include #include #include #include @@ -204,8 +205,12 @@ #define EXTENDED_CAPABILITY 0xe8 #define SLAVE_CONFIG 0xec +#define DW_I3C_DEV_NACK_RETRY_CNT_MAX 0x3 +#define DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK GENMASK(30, 29) #define DEV_ADDR_TABLE_IBI_MDB BIT(12) #define DEV_ADDR_TABLE_SIR_REJECT BIT(13) +#define DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(x) \ + FIELD_PREP(DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK, (x)) #define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) #define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) #define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) @@ -1489,6 +1494,40 @@ static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int dw_i3c_master_set_dev_nack_retry(struct i3c_master_controller *m, + unsigned long dev_nack_retry_cnt) +{ + struct dw_i3c_master *master = to_dw_i3c_master(m); + u32 reg; + int i; + + if (dev_nack_retry_cnt > DW_I3C_DEV_NACK_RETRY_CNT_MAX) { + dev_err(&master->base.dev, + "Value %ld exceeds maximum %d\n", + dev_nack_retry_cnt, DW_I3C_DEV_NACK_RETRY_CNT_MAX); + return -ERANGE; + } + + /* + * Update DAT entries for all currently attached devices. + * We directly iterate through the master's device array. + */ + for (i = 0; i < master->maxdevs; i++) { + /* Skip free/empty slots */ + if (master->free_pos & BIT(i)) + continue; + + reg = readl(master->regs + + DEV_ADDR_TABLE_LOC(master->datstartaddr, i)); + reg &= ~DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK; + reg |= DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(dev_nack_retry_cnt); + writel(reg, master->regs + + DEV_ADDR_TABLE_LOC(master->datstartaddr, i)); + } + + return 0; +} + static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .bus_init = dw_i3c_master_bus_init, .bus_cleanup = dw_i3c_master_bus_cleanup, @@ -1509,6 +1548,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, .enable_hotjoin = dw_i3c_master_enable_hotjoin, .disable_hotjoin = dw_i3c_master_disable_hotjoin, + .set_dev_nack_retry = dw_i3c_master_set_dev_nack_retry, }; /* default platform ops implementations */