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