static int cdns_i3c_master_do_daa()

in master/i3c-master-cdns.c [1132:1190]


static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
{
	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
	unsigned long olddevs, newdevs;
	int ret, slot;
	u8 addrs[MAX_DEVS] = { };
	u8 last_addr = 0;

	olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
	olddevs |= BIT(0);

	/* Prepare RR slots before launching DAA. */
	for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) {
		ret = i3c_master_get_free_addr(m, last_addr + 1);
		if (ret < 0)
			return -ENOSPC;

		last_addr = ret;
		addrs[slot] = last_addr;
		writel(prepare_rr0_dev_address(last_addr) | DEV_ID_RR0_IS_I3C,
		       master->regs + DEV_ID_RR0(slot));
		writel(0, master->regs + DEV_ID_RR1(slot));
		writel(0, master->regs + DEV_ID_RR2(slot));
	}

	ret = i3c_master_entdaa_locked(&master->base);
	if (ret && ret != I3C_ERROR_M2)
		return ret;

	newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
	newdevs &= ~olddevs;

	/*
	 * Clear all retaining registers filled during DAA. We already
	 * have the addressed assigned to them in the addrs array.
	 */
	for_each_set_bit(slot, &newdevs, master->maxdevs + 1)
		i3c_master_add_i3c_dev_locked(m, addrs[slot]);

	/*
	 * Clear slots that ended up not being used. Can be caused by I3C
	 * device creation failure or when the I3C device was already known
	 * by the system but with a different address (in this case the device
	 * already has a slot and does not need a new one).
	 */
	writel(readl(master->regs + DEVS_CTRL) |
	       master->free_rr_slots << DEVS_CTRL_DEV_CLR_SHIFT,
	       master->regs + DEVS_CTRL);

	i3c_master_defslvs_locked(&master->base);

	cdns_i3c_master_upd_i3c_scl_lim(master);

	/* Unmask Hot-Join and Mastership request interrupts. */
	i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
			       I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR);

	return 0;
}