diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 7a39be64c4e1..d6a8a7612d46 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -555,6 +555,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev, return ret; } +static void i3c_hci_dat_v1_set_curr_nack_retry(struct i3c_hci *hci, unsigned int dat_idx) +{ + mipi_i3c_hci_dat_v1.set_nack_retry(hci, dat_idx, hci->master.dev_nack_retry_count); +} + static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev) { struct i3c_master_controller *m = i3c_dev_get_master(dev); @@ -573,6 +578,7 @@ static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev) } mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret, dev->info.dyn_addr ?: dev->info.static_addr); + i3c_hci_dat_v1_set_curr_nack_retry(hci, ret); dev_data->dat_idx = ret; } i3c_dev_set_master_data(dev, dev_data); @@ -622,6 +628,7 @@ static int i3c_hci_attach_i2c_dev(struct i2c_dev_desc *dev) } mipi_i3c_hci_dat_v1.set_static_addr(hci, ret, dev->addr); mipi_i3c_hci_dat_v1.set_flags(hci, ret, DAT_0_I2C_DEVICE, 0); + i3c_hci_dat_v1_set_curr_nack_retry(hci, ret); dev_data->dat_idx = ret; i2c_dev_set_master_data(dev, dev_data); return 0; @@ -733,6 +740,23 @@ static void i3c_hci_recycle_ibi_slot(struct i3c_dev_desc *dev, hci->io->recycle_ibi_slot(hci, dev, slot); } +static int i3c_hci_set_dev_nack_retry(struct i3c_master_controller *m, unsigned int cnt) +{ + struct i3c_hci *hci = to_i3c_hci(m); + unsigned int dat_idx; + + if (hci->cmd != &mipi_i3c_hci_cmd_v1) + return -EOPNOTSUPP; + + if (cnt > FIELD_MAX(DAT_0_DEV_NACK_RETRY_CNT)) + return -ERANGE; + + for_each_set_bit(dat_idx, hci->DAT_data, hci->DAT_entries) + mipi_i3c_hci_dat_v1.set_nack_retry(hci, dat_idx, cnt); + + return 0; +} + static const struct i3c_master_controller_ops i3c_hci_ops = { .bus_init = i3c_hci_bus_init, .bus_cleanup = i3c_hci_bus_cleanup, @@ -752,6 +776,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = { .recycle_ibi_slot = i3c_hci_recycle_ibi_slot, .enable_hotjoin = i3c_hci_enable_hotjoin, .disable_hotjoin = i3c_hci_disable_hotjoin, + .set_dev_nack_retry = i3c_hci_set_dev_nack_retry, }; static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) @@ -1186,6 +1211,13 @@ static int i3c_hci_probe(struct platform_device *pdev) if (device_can_wakeup(i3c_hci_sysdev(&pdev->dev))) hci->master.ibi_wakeup = true; + /* + * HCI v1.1 onward does 1 retry for Direct CCCs anyway, so for v1.0 to + * be consistent, promote 0 to 1. + */ + if (!hci->master.dev_nack_retry_count) + hci->master.dev_nack_retry_count = 1; + return i3c_master_register(&hci->master, &pdev->dev, &i3c_hci_ops, false); } diff --git a/drivers/i3c/master/mipi-i3c-hci/dat.h b/drivers/i3c/master/mipi-i3c-hci/dat.h index 6881f19da77f..31becc6f9aec 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dat.h +++ b/drivers/i3c/master/mipi-i3c-hci/dat.h @@ -12,6 +12,7 @@ /* Global DAT flags */ #define DAT_0_I2C_DEVICE W0_BIT_(31) +#define DAT_0_DEV_NACK_RETRY_CNT W0_MASK(30, 29) #define DAT_0_SIR_REJECT W0_BIT_(13) #define DAT_0_IBI_PAYLOAD W0_BIT_(12) @@ -25,6 +26,7 @@ struct hci_dat_ops { void (*clear_flags)(struct i3c_hci *hci, unsigned int dat_idx, u32 w0, u32 w1); int (*get_index)(struct i3c_hci *hci, u8 address); void (*restore)(struct i3c_hci *hci); + void (*set_nack_retry)(struct i3c_hci *hci, unsigned int dat_idx, unsigned int cnt); }; extern const struct hci_dat_ops mipi_i3c_hci_dat_v1; diff --git a/drivers/i3c/master/mipi-i3c-hci/dat_v1.c b/drivers/i3c/master/mipi-i3c-hci/dat_v1.c index 852966aa20d9..ec0764a27c62 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dat_v1.c +++ b/drivers/i3c/master/mipi-i3c-hci/dat_v1.c @@ -24,7 +24,7 @@ #define DAT_1_AUTOCMD_VALUE W1_MASK(47, 40) #define DAT_1_AUTOCMD_MASK W1_MASK(39, 32) /* DAT_0_I2C_DEVICE W0_BIT_(31) */ -#define DAT_0_DEV_NACK_RETRY_CNT W0_MASK(30, 29) +/* DAT_0_DEV_NACK_RETRY_CNT W0_MASK(30, 29) */ #define DAT_0_RING_ID W0_MASK(28, 26) #define DAT_0_DYNADDR_PARITY W0_BIT_(23) #define DAT_0_DYNAMIC_ADDRESS W0_MASK(22, 16) @@ -189,6 +189,16 @@ static void hci_dat_v1_restore(struct i3c_hci *hci) } } +static void hci_dat_v1_set_nack_retry(struct i3c_hci *hci, unsigned int dat_idx, unsigned int cnt) +{ + u32 dat_w0; + + dat_w0 = dat_w0_read(dat_idx); + dat_w0 &= ~DAT_0_DEV_NACK_RETRY_CNT; + dat_w0 |= FIELD_PREP(DAT_0_DEV_NACK_RETRY_CNT, cnt); + dat_w0_write(dat_idx, dat_w0); +} + const struct hci_dat_ops mipi_i3c_hci_dat_v1 = { .init = hci_dat_v1_init, .alloc_entry = hci_dat_v1_alloc_entry, @@ -199,4 +209,5 @@ const struct hci_dat_ops mipi_i3c_hci_dat_v1 = { .clear_flags = hci_dat_v1_clear_flags, .get_index = hci_dat_v1_get_index, .restore = hci_dat_v1_restore, + .set_nack_retry = hci_dat_v1_set_nack_retry, };