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

i3c: dw: Add hot-join support.

Add hot-join support for dw i3c master controller.
By default, the hot-join acknowledgment is disabled, and the hardware will
automatically send the DISEC CCC when it receives the hot-join request.
Users can use the sys entry to enable it.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Link: https://lore.kernel.org/r/20240429073624.256830-1-billy_tsai@aspeedtech.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Billy Tsai and committed by
Alexandre Belloni
1d083260 29391d91

+55 -12
+53 -12
drivers/i3c/master/dw-i3c-master.c
··· 1136 1136 data->ibi_pool = NULL; 1137 1137 } 1138 1138 1139 + static void dw_i3c_master_enable_sir_signal(struct dw_i3c_master *master, bool enable) 1140 + { 1141 + u32 reg; 1142 + 1143 + reg = readl(master->regs + INTR_STATUS_EN); 1144 + reg &= ~INTR_IBI_THLD_STAT; 1145 + if (enable) 1146 + reg |= INTR_IBI_THLD_STAT; 1147 + writel(reg, master->regs + INTR_STATUS_EN); 1148 + 1149 + reg = readl(master->regs + INTR_SIGNAL_EN); 1150 + reg &= ~INTR_IBI_THLD_STAT; 1151 + if (enable) 1152 + reg |= INTR_IBI_THLD_STAT; 1153 + writel(reg, master->regs + INTR_SIGNAL_EN); 1154 + } 1155 + 1139 1156 static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, 1140 1157 struct i3c_dev_desc *dev, 1141 1158 u8 idx, bool enable) ··· 1187 1170 } 1188 1171 writel(reg, master->regs + IBI_SIR_REQ_REJECT); 1189 1172 1190 - if (global) { 1191 - reg = readl(master->regs + INTR_STATUS_EN); 1192 - reg &= ~INTR_IBI_THLD_STAT; 1193 - if (enable) 1194 - reg |= INTR_IBI_THLD_STAT; 1195 - writel(reg, master->regs + INTR_STATUS_EN); 1173 + if (global) 1174 + dw_i3c_master_enable_sir_signal(master, enable); 1196 1175 1197 - reg = readl(master->regs + INTR_SIGNAL_EN); 1198 - reg &= ~INTR_IBI_THLD_STAT; 1199 - if (enable) 1200 - reg |= INTR_IBI_THLD_STAT; 1201 - writel(reg, master->regs + INTR_SIGNAL_EN); 1202 - } 1203 1176 1204 1177 spin_unlock_irqrestore(&master->devs_lock, flags); 1178 + } 1179 + 1180 + static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m) 1181 + { 1182 + struct dw_i3c_master *master = to_dw_i3c_master(m); 1183 + 1184 + dw_i3c_master_enable_sir_signal(master, true); 1185 + writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK, 1186 + master->regs + DEVICE_CTRL); 1187 + 1188 + return 0; 1189 + } 1190 + 1191 + static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m) 1192 + { 1193 + struct dw_i3c_master *master = to_dw_i3c_master(m); 1194 + 1195 + writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 1196 + master->regs + DEVICE_CTRL); 1197 + 1198 + return 0; 1205 1199 } 1206 1200 1207 1201 static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev) ··· 1354 1326 1355 1327 if (IBI_TYPE_SIRQ(reg)) { 1356 1328 dw_i3c_master_handle_ibi_sir(master, reg); 1329 + } else if (IBI_TYPE_HJ(reg)) { 1330 + queue_work(master->base.wq, &master->hj_work); 1357 1331 } else { 1358 1332 len = IBI_QUEUE_STATUS_DATA_LEN(reg); 1359 1333 dev_info(&master->base.dev, ··· 1423 1393 .enable_ibi = dw_i3c_master_enable_ibi, 1424 1394 .disable_ibi = dw_i3c_master_disable_ibi, 1425 1395 .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, 1396 + .enable_hotjoin = dw_i3c_master_enable_hotjoin, 1397 + .disable_hotjoin = dw_i3c_master_disable_hotjoin, 1426 1398 }; 1427 1399 1428 1400 /* default platform ops implementations */ ··· 1443 1411 .init = dw_i3c_platform_init_nop, 1444 1412 .set_dat_ibi = dw_i3c_platform_set_dat_ibi_nop, 1445 1413 }; 1414 + 1415 + static void dw_i3c_hj_work(struct work_struct *work) 1416 + { 1417 + struct dw_i3c_master *master = 1418 + container_of(work, typeof(*master), hj_work); 1419 + 1420 + i3c_master_do_daa(&master->base); 1421 + } 1446 1422 1447 1423 int dw_i3c_common_probe(struct dw_i3c_master *master, 1448 1424 struct platform_device *pdev) ··· 1509 1469 if (master->ibi_capable) 1510 1470 ops = &dw_mipi_i3c_ibi_ops; 1511 1471 1472 + INIT_WORK(&master->hj_work, dw_i3c_hj_work); 1512 1473 ret = i3c_master_register(&master->base, &pdev->dev, ops, false); 1513 1474 if (ret) 1514 1475 goto err_assert_rst;
+2
drivers/i3c/master/dw-i3c-master.h
··· 57 57 58 58 /* platform-specific data */ 59 59 const struct dw_i3c_platform_ops *platform_ops; 60 + 61 + struct work_struct hj_work; 60 62 }; 61 63 62 64 struct dw_i3c_platform_ops {