in master/dw-i3c-master.c [761:824]
static int dw_i3c_master_daa(struct i3c_master_controller *m)
{
struct dw_i3c_master *master = to_dw_i3c_master(m);
struct dw_i3c_xfer *xfer;
struct dw_i3c_cmd *cmd;
u32 olddevs, newdevs;
u8 p, last_addr = 0;
int ret, pos;
olddevs = ~(master->free_pos);
/* Prepare DAT before launching DAA. */
for (pos = 0; pos < master->maxdevs; pos++) {
if (olddevs & BIT(pos))
continue;
ret = i3c_master_get_free_addr(m, last_addr + 1);
if (ret < 0)
return -ENOSPC;
master->addrs[pos] = ret;
p = even_parity(ret);
last_addr = ret;
ret |= (p << 7);
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret),
master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, pos));
}
xfer = dw_i3c_master_alloc_xfer(master, 1);
if (!xfer)
return -ENOMEM;
pos = dw_i3c_master_get_free_pos(master);
if (pos < 0) {
dw_i3c_master_free_xfer(xfer);
return pos;
}
cmd = &xfer->cmds[0];
cmd->cmd_hi = 0x1;
cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) |
COMMAND_PORT_DEV_INDEX(pos) |
COMMAND_PORT_CMD(I3C_CCC_ENTDAA) |
COMMAND_PORT_ADDR_ASSGN_CMD |
COMMAND_PORT_TOC |
COMMAND_PORT_ROC;
dw_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
dw_i3c_master_dequeue_xfer(master, xfer);
newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0);
newdevs &= ~olddevs;
for (pos = 0; pos < master->maxdevs; pos++) {
if (newdevs & BIT(pos))
i3c_master_add_i3c_dev_locked(m, master->addrs[pos]);
}
dw_i3c_master_free_xfer(xfer);
return 0;
}