162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2020, MIPI Alliance, Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Nicolas Pitre <npitre@baylibre.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * I3C HCI v1.0/v1.1 Command Descriptor Handling
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci#include <linux/i3c/master.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "hci.h"
1462306a36Sopenharmony_ci#include "cmd.h"
1562306a36Sopenharmony_ci#include "dat.h"
1662306a36Sopenharmony_ci#include "dct.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Address Assignment Command
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define CMD_0_ATTR_A			FIELD_PREP(CMD_0_ATTR, 0x2)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define CMD_A0_TOC				   W0_BIT_(31)
2662306a36Sopenharmony_ci#define CMD_A0_ROC				   W0_BIT_(30)
2762306a36Sopenharmony_ci#define CMD_A0_DEV_COUNT(v)		FIELD_PREP(W0_MASK(29, 26), v)
2862306a36Sopenharmony_ci#define CMD_A0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)
2962306a36Sopenharmony_ci#define CMD_A0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)
3062306a36Sopenharmony_ci#define CMD_A0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Immediate Data Transfer Command
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define CMD_0_ATTR_I			FIELD_PREP(CMD_0_ATTR, 0x1)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define CMD_I1_DATA_BYTE_4(v)		FIELD_PREP(W1_MASK(63, 56), v)
3962306a36Sopenharmony_ci#define CMD_I1_DATA_BYTE_3(v)		FIELD_PREP(W1_MASK(55, 48), v)
4062306a36Sopenharmony_ci#define CMD_I1_DATA_BYTE_2(v)		FIELD_PREP(W1_MASK(47, 40), v)
4162306a36Sopenharmony_ci#define CMD_I1_DATA_BYTE_1(v)		FIELD_PREP(W1_MASK(39, 32), v)
4262306a36Sopenharmony_ci#define CMD_I1_DEF_BYTE(v)		FIELD_PREP(W1_MASK(39, 32), v)
4362306a36Sopenharmony_ci#define CMD_I0_TOC				   W0_BIT_(31)
4462306a36Sopenharmony_ci#define CMD_I0_ROC				   W0_BIT_(30)
4562306a36Sopenharmony_ci#define CMD_I0_RNW				   W0_BIT_(29)
4662306a36Sopenharmony_ci#define CMD_I0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)
4762306a36Sopenharmony_ci#define CMD_I0_DTT(v)			FIELD_PREP(W0_MASK(25, 23), v)
4862306a36Sopenharmony_ci#define CMD_I0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)
4962306a36Sopenharmony_ci#define CMD_I0_CP				   W0_BIT_(15)
5062306a36Sopenharmony_ci#define CMD_I0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)
5162306a36Sopenharmony_ci#define CMD_I0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Regular Data Transfer Command
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define CMD_0_ATTR_R			FIELD_PREP(CMD_0_ATTR, 0x0)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define CMD_R1_DATA_LENGTH(v)		FIELD_PREP(W1_MASK(63, 48), v)
6062306a36Sopenharmony_ci#define CMD_R1_DEF_BYTE(v)		FIELD_PREP(W1_MASK(39, 32), v)
6162306a36Sopenharmony_ci#define CMD_R0_TOC				   W0_BIT_(31)
6262306a36Sopenharmony_ci#define CMD_R0_ROC				   W0_BIT_(30)
6362306a36Sopenharmony_ci#define CMD_R0_RNW				   W0_BIT_(29)
6462306a36Sopenharmony_ci#define CMD_R0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)
6562306a36Sopenharmony_ci#define CMD_R0_DBP				   W0_BIT_(25)
6662306a36Sopenharmony_ci#define CMD_R0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)
6762306a36Sopenharmony_ci#define CMD_R0_CP				   W0_BIT_(15)
6862306a36Sopenharmony_ci#define CMD_R0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)
6962306a36Sopenharmony_ci#define CMD_R0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * Combo Transfer (Write + Write/Read) Command
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define CMD_0_ATTR_C			FIELD_PREP(CMD_0_ATTR, 0x3)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define CMD_C1_DATA_LENGTH(v)		FIELD_PREP(W1_MASK(63, 48), v)
7862306a36Sopenharmony_ci#define CMD_C1_OFFSET(v)		FIELD_PREP(W1_MASK(47, 32), v)
7962306a36Sopenharmony_ci#define CMD_C0_TOC				   W0_BIT_(31)
8062306a36Sopenharmony_ci#define CMD_C0_ROC				   W0_BIT_(30)
8162306a36Sopenharmony_ci#define CMD_C0_RNW				   W0_BIT_(29)
8262306a36Sopenharmony_ci#define CMD_C0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)
8362306a36Sopenharmony_ci#define CMD_C0_16_BIT_SUBOFFSET			   W0_BIT_(25)
8462306a36Sopenharmony_ci#define CMD_C0_FIRST_PHASE_MODE			   W0_BIT_(24)
8562306a36Sopenharmony_ci#define CMD_C0_DATA_LENGTH_POSITION(v)	FIELD_PREP(W0_MASK(23, 22), v)
8662306a36Sopenharmony_ci#define CMD_C0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)
8762306a36Sopenharmony_ci#define CMD_C0_CP				   W0_BIT_(15)
8862306a36Sopenharmony_ci#define CMD_C0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)
8962306a36Sopenharmony_ci#define CMD_C0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * Internal Control Command
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define CMD_0_ATTR_M			FIELD_PREP(CMD_0_ATTR, 0x7)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define CMD_M1_VENDOR_SPECIFIC			   W1_MASK(63, 32)
9862306a36Sopenharmony_ci#define CMD_M0_MIPI_RESERVED			   W0_MASK(31, 12)
9962306a36Sopenharmony_ci#define CMD_M0_MIPI_CMD				   W0_MASK(11,  8)
10062306a36Sopenharmony_ci#define CMD_M0_VENDOR_INFO_PRESENT		   W0_BIT_( 7)
10162306a36Sopenharmony_ci#define CMD_M0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* Data Transfer Speed and Mode */
10562306a36Sopenharmony_cienum hci_cmd_mode {
10662306a36Sopenharmony_ci	MODE_I3C_SDR0		= 0x0,
10762306a36Sopenharmony_ci	MODE_I3C_SDR1		= 0x1,
10862306a36Sopenharmony_ci	MODE_I3C_SDR2		= 0x2,
10962306a36Sopenharmony_ci	MODE_I3C_SDR3		= 0x3,
11062306a36Sopenharmony_ci	MODE_I3C_SDR4		= 0x4,
11162306a36Sopenharmony_ci	MODE_I3C_HDR_TSx	= 0x5,
11262306a36Sopenharmony_ci	MODE_I3C_HDR_DDR	= 0x6,
11362306a36Sopenharmony_ci	MODE_I3C_HDR_BT		= 0x7,
11462306a36Sopenharmony_ci	MODE_I3C_Fm_FmP		= 0x8,
11562306a36Sopenharmony_ci	MODE_I2C_Fm		= 0x0,
11662306a36Sopenharmony_ci	MODE_I2C_FmP		= 0x1,
11762306a36Sopenharmony_ci	MODE_I2C_UD1		= 0x2,
11862306a36Sopenharmony_ci	MODE_I2C_UD2		= 0x3,
11962306a36Sopenharmony_ci	MODE_I2C_UD3		= 0x4,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic enum hci_cmd_mode get_i3c_mode(struct i3c_hci *hci)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct i3c_bus *bus = i3c_master_get_bus(&hci->master);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (bus->scl_rate.i3c >= 12500000)
12762306a36Sopenharmony_ci		return MODE_I3C_SDR0;
12862306a36Sopenharmony_ci	if (bus->scl_rate.i3c > 8000000)
12962306a36Sopenharmony_ci		return MODE_I3C_SDR1;
13062306a36Sopenharmony_ci	if (bus->scl_rate.i3c > 6000000)
13162306a36Sopenharmony_ci		return MODE_I3C_SDR2;
13262306a36Sopenharmony_ci	if (bus->scl_rate.i3c > 4000000)
13362306a36Sopenharmony_ci		return MODE_I3C_SDR3;
13462306a36Sopenharmony_ci	if (bus->scl_rate.i3c > 2000000)
13562306a36Sopenharmony_ci		return MODE_I3C_SDR4;
13662306a36Sopenharmony_ci	return MODE_I3C_Fm_FmP;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic enum hci_cmd_mode get_i2c_mode(struct i3c_hci *hci)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct i3c_bus *bus = i3c_master_get_bus(&hci->master);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (bus->scl_rate.i2c >= 1000000)
14462306a36Sopenharmony_ci		return MODE_I2C_FmP;
14562306a36Sopenharmony_ci	return MODE_I2C_Fm;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void fill_data_bytes(struct hci_xfer *xfer, u8 *data,
14962306a36Sopenharmony_ci			    unsigned int data_len)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	xfer->cmd_desc[1] = 0;
15262306a36Sopenharmony_ci	switch (data_len) {
15362306a36Sopenharmony_ci	case 4:
15462306a36Sopenharmony_ci		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_4(data[3]);
15562306a36Sopenharmony_ci		fallthrough;
15662306a36Sopenharmony_ci	case 3:
15762306a36Sopenharmony_ci		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_3(data[2]);
15862306a36Sopenharmony_ci		fallthrough;
15962306a36Sopenharmony_ci	case 2:
16062306a36Sopenharmony_ci		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_2(data[1]);
16162306a36Sopenharmony_ci		fallthrough;
16262306a36Sopenharmony_ci	case 1:
16362306a36Sopenharmony_ci		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_1(data[0]);
16462306a36Sopenharmony_ci		fallthrough;
16562306a36Sopenharmony_ci	case 0:
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	/* we consumed all the data with the cmd descriptor */
16962306a36Sopenharmony_ci	xfer->data = NULL;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int hci_cmd_v1_prep_ccc(struct i3c_hci *hci,
17362306a36Sopenharmony_ci			       struct hci_xfer *xfer,
17462306a36Sopenharmony_ci			       u8 ccc_addr, u8 ccc_cmd, bool raw)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	unsigned int dat_idx = 0;
17762306a36Sopenharmony_ci	enum hci_cmd_mode mode = get_i3c_mode(hci);
17862306a36Sopenharmony_ci	u8 *data = xfer->data;
17962306a36Sopenharmony_ci	unsigned int data_len = xfer->data_len;
18062306a36Sopenharmony_ci	bool rnw = xfer->rnw;
18162306a36Sopenharmony_ci	int ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* this should never happen */
18462306a36Sopenharmony_ci	if (WARN_ON(raw))
18562306a36Sopenharmony_ci		return -EINVAL;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (ccc_addr != I3C_BROADCAST_ADDR) {
18862306a36Sopenharmony_ci		ret = mipi_i3c_hci_dat_v1.get_index(hci, ccc_addr);
18962306a36Sopenharmony_ci		if (ret < 0)
19062306a36Sopenharmony_ci			return ret;
19162306a36Sopenharmony_ci		dat_idx = ret;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	xfer->cmd_tid = hci_get_tid();
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!rnw && data_len <= 4) {
19762306a36Sopenharmony_ci		/* we use an Immediate Data Transfer Command */
19862306a36Sopenharmony_ci		xfer->cmd_desc[0] =
19962306a36Sopenharmony_ci			CMD_0_ATTR_I |
20062306a36Sopenharmony_ci			CMD_I0_TID(xfer->cmd_tid) |
20162306a36Sopenharmony_ci			CMD_I0_CMD(ccc_cmd) | CMD_I0_CP |
20262306a36Sopenharmony_ci			CMD_I0_DEV_INDEX(dat_idx) |
20362306a36Sopenharmony_ci			CMD_I0_DTT(data_len) |
20462306a36Sopenharmony_ci			CMD_I0_MODE(mode);
20562306a36Sopenharmony_ci		fill_data_bytes(xfer, data, data_len);
20662306a36Sopenharmony_ci	} else {
20762306a36Sopenharmony_ci		/* we use a Regular Data Transfer Command */
20862306a36Sopenharmony_ci		xfer->cmd_desc[0] =
20962306a36Sopenharmony_ci			CMD_0_ATTR_R |
21062306a36Sopenharmony_ci			CMD_R0_TID(xfer->cmd_tid) |
21162306a36Sopenharmony_ci			CMD_R0_CMD(ccc_cmd) | CMD_R0_CP |
21262306a36Sopenharmony_ci			CMD_R0_DEV_INDEX(dat_idx) |
21362306a36Sopenharmony_ci			CMD_R0_MODE(mode) |
21462306a36Sopenharmony_ci			(rnw ? CMD_R0_RNW : 0);
21562306a36Sopenharmony_ci		xfer->cmd_desc[1] =
21662306a36Sopenharmony_ci			CMD_R1_DATA_LENGTH(data_len);
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,
22362306a36Sopenharmony_ci				     struct i3c_dev_desc *dev,
22462306a36Sopenharmony_ci				     struct hci_xfer *xfer)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
22762306a36Sopenharmony_ci	unsigned int dat_idx = dev_data->dat_idx;
22862306a36Sopenharmony_ci	enum hci_cmd_mode mode = get_i3c_mode(hci);
22962306a36Sopenharmony_ci	u8 *data = xfer->data;
23062306a36Sopenharmony_ci	unsigned int data_len = xfer->data_len;
23162306a36Sopenharmony_ci	bool rnw = xfer->rnw;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	xfer->cmd_tid = hci_get_tid();
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (!rnw && data_len <= 4) {
23662306a36Sopenharmony_ci		/* we use an Immediate Data Transfer Command */
23762306a36Sopenharmony_ci		xfer->cmd_desc[0] =
23862306a36Sopenharmony_ci			CMD_0_ATTR_I |
23962306a36Sopenharmony_ci			CMD_I0_TID(xfer->cmd_tid) |
24062306a36Sopenharmony_ci			CMD_I0_DEV_INDEX(dat_idx) |
24162306a36Sopenharmony_ci			CMD_I0_DTT(data_len) |
24262306a36Sopenharmony_ci			CMD_I0_MODE(mode);
24362306a36Sopenharmony_ci		fill_data_bytes(xfer, data, data_len);
24462306a36Sopenharmony_ci	} else {
24562306a36Sopenharmony_ci		/* we use a Regular Data Transfer Command */
24662306a36Sopenharmony_ci		xfer->cmd_desc[0] =
24762306a36Sopenharmony_ci			CMD_0_ATTR_R |
24862306a36Sopenharmony_ci			CMD_R0_TID(xfer->cmd_tid) |
24962306a36Sopenharmony_ci			CMD_R0_DEV_INDEX(dat_idx) |
25062306a36Sopenharmony_ci			CMD_R0_MODE(mode) |
25162306a36Sopenharmony_ci			(rnw ? CMD_R0_RNW : 0);
25262306a36Sopenharmony_ci		xfer->cmd_desc[1] =
25362306a36Sopenharmony_ci			CMD_R1_DATA_LENGTH(data_len);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic void hci_cmd_v1_prep_i2c_xfer(struct i3c_hci *hci,
25862306a36Sopenharmony_ci				     struct i2c_dev_desc *dev,
25962306a36Sopenharmony_ci				     struct hci_xfer *xfer)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct i3c_hci_dev_data *dev_data = i2c_dev_get_master_data(dev);
26262306a36Sopenharmony_ci	unsigned int dat_idx = dev_data->dat_idx;
26362306a36Sopenharmony_ci	enum hci_cmd_mode mode = get_i2c_mode(hci);
26462306a36Sopenharmony_ci	u8 *data = xfer->data;
26562306a36Sopenharmony_ci	unsigned int data_len = xfer->data_len;
26662306a36Sopenharmony_ci	bool rnw = xfer->rnw;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	xfer->cmd_tid = hci_get_tid();
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!rnw && data_len <= 4) {
27162306a36Sopenharmony_ci		/* we use an Immediate Data Transfer Command */
27262306a36Sopenharmony_ci		xfer->cmd_desc[0] =
27362306a36Sopenharmony_ci			CMD_0_ATTR_I |
27462306a36Sopenharmony_ci			CMD_I0_TID(xfer->cmd_tid) |
27562306a36Sopenharmony_ci			CMD_I0_DEV_INDEX(dat_idx) |
27662306a36Sopenharmony_ci			CMD_I0_DTT(data_len) |
27762306a36Sopenharmony_ci			CMD_I0_MODE(mode);
27862306a36Sopenharmony_ci		fill_data_bytes(xfer, data, data_len);
27962306a36Sopenharmony_ci	} else {
28062306a36Sopenharmony_ci		/* we use a Regular Data Transfer Command */
28162306a36Sopenharmony_ci		xfer->cmd_desc[0] =
28262306a36Sopenharmony_ci			CMD_0_ATTR_R |
28362306a36Sopenharmony_ci			CMD_R0_TID(xfer->cmd_tid) |
28462306a36Sopenharmony_ci			CMD_R0_DEV_INDEX(dat_idx) |
28562306a36Sopenharmony_ci			CMD_R0_MODE(mode) |
28662306a36Sopenharmony_ci			(rnw ? CMD_R0_RNW : 0);
28762306a36Sopenharmony_ci		xfer->cmd_desc[1] =
28862306a36Sopenharmony_ci			CMD_R1_DATA_LENGTH(data_len);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic int hci_cmd_v1_daa(struct i3c_hci *hci)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct hci_xfer *xfer;
29562306a36Sopenharmony_ci	int ret, dat_idx = -1;
29662306a36Sopenharmony_ci	u8 next_addr = 0;
29762306a36Sopenharmony_ci	u64 pid;
29862306a36Sopenharmony_ci	unsigned int dcr, bcr;
29962306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(done);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	xfer = hci_alloc_xfer(2);
30262306a36Sopenharmony_ci	if (!xfer)
30362306a36Sopenharmony_ci		return -ENOMEM;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/*
30662306a36Sopenharmony_ci	 * Simple for now: we allocate a temporary DAT entry, do a single
30762306a36Sopenharmony_ci	 * DAA, register the device which will allocate its own DAT entry
30862306a36Sopenharmony_ci	 * via the core callback, then free the temporary DAT entry.
30962306a36Sopenharmony_ci	 * Loop until there is no more devices to assign an address to.
31062306a36Sopenharmony_ci	 * Yes, there is room for improvements.
31162306a36Sopenharmony_ci	 */
31262306a36Sopenharmony_ci	for (;;) {
31362306a36Sopenharmony_ci		ret = mipi_i3c_hci_dat_v1.alloc_entry(hci);
31462306a36Sopenharmony_ci		if (ret < 0)
31562306a36Sopenharmony_ci			break;
31662306a36Sopenharmony_ci		dat_idx = ret;
31762306a36Sopenharmony_ci		ret = i3c_master_get_free_addr(&hci->master, next_addr);
31862306a36Sopenharmony_ci		if (ret < 0)
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		next_addr = ret;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		DBG("next_addr = 0x%02x, DAA using DAT %d", next_addr, dat_idx);
32362306a36Sopenharmony_ci		mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, dat_idx, next_addr);
32462306a36Sopenharmony_ci		mipi_i3c_hci_dct_index_reset(hci);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		xfer->cmd_tid = hci_get_tid();
32762306a36Sopenharmony_ci		xfer->cmd_desc[0] =
32862306a36Sopenharmony_ci			CMD_0_ATTR_A |
32962306a36Sopenharmony_ci			CMD_A0_TID(xfer->cmd_tid) |
33062306a36Sopenharmony_ci			CMD_A0_CMD(I3C_CCC_ENTDAA) |
33162306a36Sopenharmony_ci			CMD_A0_DEV_INDEX(dat_idx) |
33262306a36Sopenharmony_ci			CMD_A0_DEV_COUNT(1) |
33362306a36Sopenharmony_ci			CMD_A0_ROC | CMD_A0_TOC;
33462306a36Sopenharmony_ci		xfer->cmd_desc[1] = 0;
33562306a36Sopenharmony_ci		hci->io->queue_xfer(hci, xfer, 1);
33662306a36Sopenharmony_ci		if (!wait_for_completion_timeout(&done, HZ) &&
33762306a36Sopenharmony_ci		    hci->io->dequeue_xfer(hci, xfer, 1)) {
33862306a36Sopenharmony_ci			ret = -ETIME;
33962306a36Sopenharmony_ci			break;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci		if (RESP_STATUS(xfer[0].response) == RESP_ERR_NACK &&
34262306a36Sopenharmony_ci		    RESP_DATA_LENGTH(xfer->response) == 1) {
34362306a36Sopenharmony_ci			ret = 0;  /* no more devices to be assigned */
34462306a36Sopenharmony_ci			break;
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci		if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
34762306a36Sopenharmony_ci			ret = -EIO;
34862306a36Sopenharmony_ci			break;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		i3c_hci_dct_get_val(hci, 0, &pid, &dcr, &bcr);
35262306a36Sopenharmony_ci		DBG("assigned address %#x to device PID=0x%llx DCR=%#x BCR=%#x",
35362306a36Sopenharmony_ci		    next_addr, pid, dcr, bcr);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
35662306a36Sopenharmony_ci		dat_idx = -1;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		/*
35962306a36Sopenharmony_ci		 * TODO: Extend the subsystem layer to allow for registering
36062306a36Sopenharmony_ci		 * new device and provide BCR/DCR/PID at the same time.
36162306a36Sopenharmony_ci		 */
36262306a36Sopenharmony_ci		ret = i3c_master_add_i3c_dev_locked(&hci->master, next_addr);
36362306a36Sopenharmony_ci		if (ret)
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (dat_idx >= 0)
36862306a36Sopenharmony_ci		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
36962306a36Sopenharmony_ci	hci_free_xfer(xfer, 1);
37062306a36Sopenharmony_ci	return ret;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciconst struct hci_cmd_ops mipi_i3c_hci_cmd_v1 = {
37462306a36Sopenharmony_ci	.prep_ccc		= hci_cmd_v1_prep_ccc,
37562306a36Sopenharmony_ci	.prep_i3c_xfer		= hci_cmd_v1_prep_i3c_xfer,
37662306a36Sopenharmony_ci	.prep_i2c_xfer		= hci_cmd_v1_prep_i2c_xfer,
37762306a36Sopenharmony_ci	.perform_daa		= hci_cmd_v1_daa,
37862306a36Sopenharmony_ci};
379