Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

i3c: dw: Add support for Device NACK Retry configuration

The DesignWare I3C controller supports automatically retrying transactions
when a device NACKs. This is useful for slave devices that may be
temporarily busy and not ready to respond immediately.

Add new ops to configure all active DAT entry with dev_nack_retry during
runtime. Returns error when value exceeds hw specified limit.

Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/f09ee67e61d31f0a12a0bf48f01e9057ca9e2fb7.1765529948.git.adrianhoyin.ng@altera.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Adrian Ng Ho Yin and committed by
Alexandre Belloni
ec17f143 b58f47eb

+40
+40
drivers/i3c/master/dw-i3c-master.c
··· 5 5 * Author: Vitor Soares <vitor.soares@synopsys.com> 6 6 */ 7 7 8 + #include <linux/bitfield.h> 8 9 #include <linux/bitops.h> 9 10 #include <linux/clk.h> 10 11 #include <linux/completion.h> ··· 205 204 #define EXTENDED_CAPABILITY 0xe8 206 205 #define SLAVE_CONFIG 0xec 207 206 207 + #define DW_I3C_DEV_NACK_RETRY_CNT_MAX 0x3 208 + #define DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK GENMASK(30, 29) 208 209 #define DEV_ADDR_TABLE_IBI_MDB BIT(12) 209 210 #define DEV_ADDR_TABLE_SIR_REJECT BIT(13) 211 + #define DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(x) \ 212 + FIELD_PREP(DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK, (x)) 210 213 #define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) 211 214 #define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) 212 215 #define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) ··· 1494 1489 return IRQ_HANDLED; 1495 1490 } 1496 1491 1492 + static int dw_i3c_master_set_dev_nack_retry(struct i3c_master_controller *m, 1493 + unsigned long dev_nack_retry_cnt) 1494 + { 1495 + struct dw_i3c_master *master = to_dw_i3c_master(m); 1496 + u32 reg; 1497 + int i; 1498 + 1499 + if (dev_nack_retry_cnt > DW_I3C_DEV_NACK_RETRY_CNT_MAX) { 1500 + dev_err(&master->base.dev, 1501 + "Value %ld exceeds maximum %d\n", 1502 + dev_nack_retry_cnt, DW_I3C_DEV_NACK_RETRY_CNT_MAX); 1503 + return -ERANGE; 1504 + } 1505 + 1506 + /* 1507 + * Update DAT entries for all currently attached devices. 1508 + * We directly iterate through the master's device array. 1509 + */ 1510 + for (i = 0; i < master->maxdevs; i++) { 1511 + /* Skip free/empty slots */ 1512 + if (master->free_pos & BIT(i)) 1513 + continue; 1514 + 1515 + reg = readl(master->regs + 1516 + DEV_ADDR_TABLE_LOC(master->datstartaddr, i)); 1517 + reg &= ~DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK; 1518 + reg |= DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(dev_nack_retry_cnt); 1519 + writel(reg, master->regs + 1520 + DEV_ADDR_TABLE_LOC(master->datstartaddr, i)); 1521 + } 1522 + 1523 + return 0; 1524 + } 1525 + 1497 1526 static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { 1498 1527 .bus_init = dw_i3c_master_bus_init, 1499 1528 .bus_cleanup = dw_i3c_master_bus_cleanup, ··· 1548 1509 .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, 1549 1510 .enable_hotjoin = dw_i3c_master_enable_hotjoin, 1550 1511 .disable_hotjoin = dw_i3c_master_disable_hotjoin, 1512 + .set_dev_nack_retry = dw_i3c_master_set_dev_nack_retry, 1551 1513 }; 1552 1514 1553 1515 /* default platform ops implementations */