brintos

brintos / linux-shallow public Read only

0
0
Text · 10.0 KiB · dd63609 Raw
379 lines · c
1// SPDX-License-Identifier: BSD-3-Clause2/*3 * Copyright (c) 2020, MIPI Alliance, Inc.4 *5 * Author: Nicolas Pitre <npitre@baylibre.com>6 *7 * I3C HCI v1.0/v1.1 Command Descriptor Handling8 */9 10#include <linux/bitfield.h>11#include <linux/i3c/master.h>12 13#include "hci.h"14#include "cmd.h"15#include "dat.h"16#include "dct.h"17 18 19/*20 * Address Assignment Command21 */22 23#define CMD_0_ATTR_A			FIELD_PREP(CMD_0_ATTR, 0x2)24 25#define CMD_A0_TOC				   W0_BIT_(31)26#define CMD_A0_ROC				   W0_BIT_(30)27#define CMD_A0_DEV_COUNT(v)		FIELD_PREP(W0_MASK(29, 26), v)28#define CMD_A0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)29#define CMD_A0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)30#define CMD_A0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)31 32/*33 * Immediate Data Transfer Command34 */35 36#define CMD_0_ATTR_I			FIELD_PREP(CMD_0_ATTR, 0x1)37 38#define CMD_I1_DATA_BYTE_4(v)		FIELD_PREP(W1_MASK(63, 56), v)39#define CMD_I1_DATA_BYTE_3(v)		FIELD_PREP(W1_MASK(55, 48), v)40#define CMD_I1_DATA_BYTE_2(v)		FIELD_PREP(W1_MASK(47, 40), v)41#define CMD_I1_DATA_BYTE_1(v)		FIELD_PREP(W1_MASK(39, 32), v)42#define CMD_I1_DEF_BYTE(v)		FIELD_PREP(W1_MASK(39, 32), v)43#define CMD_I0_TOC				   W0_BIT_(31)44#define CMD_I0_ROC				   W0_BIT_(30)45#define CMD_I0_RNW				   W0_BIT_(29)46#define CMD_I0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)47#define CMD_I0_DTT(v)			FIELD_PREP(W0_MASK(25, 23), v)48#define CMD_I0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)49#define CMD_I0_CP				   W0_BIT_(15)50#define CMD_I0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)51#define CMD_I0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)52 53/*54 * Regular Data Transfer Command55 */56 57#define CMD_0_ATTR_R			FIELD_PREP(CMD_0_ATTR, 0x0)58 59#define CMD_R1_DATA_LENGTH(v)		FIELD_PREP(W1_MASK(63, 48), v)60#define CMD_R1_DEF_BYTE(v)		FIELD_PREP(W1_MASK(39, 32), v)61#define CMD_R0_TOC				   W0_BIT_(31)62#define CMD_R0_ROC				   W0_BIT_(30)63#define CMD_R0_RNW				   W0_BIT_(29)64#define CMD_R0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)65#define CMD_R0_DBP				   W0_BIT_(25)66#define CMD_R0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)67#define CMD_R0_CP				   W0_BIT_(15)68#define CMD_R0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)69#define CMD_R0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)70 71/*72 * Combo Transfer (Write + Write/Read) Command73 */74 75#define CMD_0_ATTR_C			FIELD_PREP(CMD_0_ATTR, 0x3)76 77#define CMD_C1_DATA_LENGTH(v)		FIELD_PREP(W1_MASK(63, 48), v)78#define CMD_C1_OFFSET(v)		FIELD_PREP(W1_MASK(47, 32), v)79#define CMD_C0_TOC				   W0_BIT_(31)80#define CMD_C0_ROC				   W0_BIT_(30)81#define CMD_C0_RNW				   W0_BIT_(29)82#define CMD_C0_MODE(v)			FIELD_PREP(W0_MASK(28, 26), v)83#define CMD_C0_16_BIT_SUBOFFSET			   W0_BIT_(25)84#define CMD_C0_FIRST_PHASE_MODE			   W0_BIT_(24)85#define CMD_C0_DATA_LENGTH_POSITION(v)	FIELD_PREP(W0_MASK(23, 22), v)86#define CMD_C0_DEV_INDEX(v)		FIELD_PREP(W0_MASK(20, 16), v)87#define CMD_C0_CP				   W0_BIT_(15)88#define CMD_C0_CMD(v)			FIELD_PREP(W0_MASK(14,  7), v)89#define CMD_C0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)90 91/*92 * Internal Control Command93 */94 95#define CMD_0_ATTR_M			FIELD_PREP(CMD_0_ATTR, 0x7)96 97#define CMD_M1_VENDOR_SPECIFIC			   W1_MASK(63, 32)98#define CMD_M0_MIPI_RESERVED			   W0_MASK(31, 12)99#define CMD_M0_MIPI_CMD				   W0_MASK(11,  8)100#define CMD_M0_VENDOR_INFO_PRESENT		   W0_BIT_( 7)101#define CMD_M0_TID(v)			FIELD_PREP(W0_MASK( 6,  3), v)102 103 104/* Data Transfer Speed and Mode */105enum hci_cmd_mode {106	MODE_I3C_SDR0		= 0x0,107	MODE_I3C_SDR1		= 0x1,108	MODE_I3C_SDR2		= 0x2,109	MODE_I3C_SDR3		= 0x3,110	MODE_I3C_SDR4		= 0x4,111	MODE_I3C_HDR_TSx	= 0x5,112	MODE_I3C_HDR_DDR	= 0x6,113	MODE_I3C_HDR_BT		= 0x7,114	MODE_I3C_Fm_FmP		= 0x8,115	MODE_I2C_Fm		= 0x0,116	MODE_I2C_FmP		= 0x1,117	MODE_I2C_UD1		= 0x2,118	MODE_I2C_UD2		= 0x3,119	MODE_I2C_UD3		= 0x4,120};121 122static enum hci_cmd_mode get_i3c_mode(struct i3c_hci *hci)123{124	struct i3c_bus *bus = i3c_master_get_bus(&hci->master);125 126	if (bus->scl_rate.i3c > 8000000)127		return MODE_I3C_SDR0;128	if (bus->scl_rate.i3c > 6000000)129		return MODE_I3C_SDR1;130	if (bus->scl_rate.i3c > 4000000)131		return MODE_I3C_SDR2;132	if (bus->scl_rate.i3c > 2000000)133		return MODE_I3C_SDR3;134	return MODE_I3C_SDR4;135}136 137static enum hci_cmd_mode get_i2c_mode(struct i3c_hci *hci)138{139	struct i3c_bus *bus = i3c_master_get_bus(&hci->master);140 141	if (bus->scl_rate.i2c >= 1000000)142		return MODE_I2C_FmP;143	return MODE_I2C_Fm;144}145 146static void fill_data_bytes(struct hci_xfer *xfer, u8 *data,147			    unsigned int data_len)148{149	xfer->cmd_desc[1] = 0;150	switch (data_len) {151	case 4:152		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_4(data[3]);153		fallthrough;154	case 3:155		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_3(data[2]);156		fallthrough;157	case 2:158		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_2(data[1]);159		fallthrough;160	case 1:161		xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_1(data[0]);162		fallthrough;163	case 0:164		break;165	}166	/* we consumed all the data with the cmd descriptor */167	xfer->data = NULL;168}169 170static int hci_cmd_v1_prep_ccc(struct i3c_hci *hci,171			       struct hci_xfer *xfer,172			       u8 ccc_addr, u8 ccc_cmd, bool raw)173{174	unsigned int dat_idx = 0;175	enum hci_cmd_mode mode = get_i3c_mode(hci);176	u8 *data = xfer->data;177	unsigned int data_len = xfer->data_len;178	bool rnw = xfer->rnw;179	int ret;180 181	/* this should never happen */182	if (WARN_ON(raw))183		return -EINVAL;184 185	if (ccc_addr != I3C_BROADCAST_ADDR) {186		ret = mipi_i3c_hci_dat_v1.get_index(hci, ccc_addr);187		if (ret < 0)188			return ret;189		dat_idx = ret;190	}191 192	xfer->cmd_tid = hci_get_tid();193 194	if (!rnw && data_len <= 4) {195		/* we use an Immediate Data Transfer Command */196		xfer->cmd_desc[0] =197			CMD_0_ATTR_I |198			CMD_I0_TID(xfer->cmd_tid) |199			CMD_I0_CMD(ccc_cmd) | CMD_I0_CP |200			CMD_I0_DEV_INDEX(dat_idx) |201			CMD_I0_DTT(data_len) |202			CMD_I0_MODE(mode);203		fill_data_bytes(xfer, data, data_len);204	} else {205		/* we use a Regular Data Transfer Command */206		xfer->cmd_desc[0] =207			CMD_0_ATTR_R |208			CMD_R0_TID(xfer->cmd_tid) |209			CMD_R0_CMD(ccc_cmd) | CMD_R0_CP |210			CMD_R0_DEV_INDEX(dat_idx) |211			CMD_R0_MODE(mode) |212			(rnw ? CMD_R0_RNW : 0);213		xfer->cmd_desc[1] =214			CMD_R1_DATA_LENGTH(data_len);215	}216 217	return 0;218}219 220static void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,221				     struct i3c_dev_desc *dev,222				     struct hci_xfer *xfer)223{224	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);225	unsigned int dat_idx = dev_data->dat_idx;226	enum hci_cmd_mode mode = get_i3c_mode(hci);227	u8 *data = xfer->data;228	unsigned int data_len = xfer->data_len;229	bool rnw = xfer->rnw;230 231	xfer->cmd_tid = hci_get_tid();232 233	if (!rnw && data_len <= 4) {234		/* we use an Immediate Data Transfer Command */235		xfer->cmd_desc[0] =236			CMD_0_ATTR_I |237			CMD_I0_TID(xfer->cmd_tid) |238			CMD_I0_DEV_INDEX(dat_idx) |239			CMD_I0_DTT(data_len) |240			CMD_I0_MODE(mode);241		fill_data_bytes(xfer, data, data_len);242	} else {243		/* we use a Regular Data Transfer Command */244		xfer->cmd_desc[0] =245			CMD_0_ATTR_R |246			CMD_R0_TID(xfer->cmd_tid) |247			CMD_R0_DEV_INDEX(dat_idx) |248			CMD_R0_MODE(mode) |249			(rnw ? CMD_R0_RNW : 0);250		xfer->cmd_desc[1] =251			CMD_R1_DATA_LENGTH(data_len);252	}253}254 255static void hci_cmd_v1_prep_i2c_xfer(struct i3c_hci *hci,256				     struct i2c_dev_desc *dev,257				     struct hci_xfer *xfer)258{259	struct i3c_hci_dev_data *dev_data = i2c_dev_get_master_data(dev);260	unsigned int dat_idx = dev_data->dat_idx;261	enum hci_cmd_mode mode = get_i2c_mode(hci);262	u8 *data = xfer->data;263	unsigned int data_len = xfer->data_len;264	bool rnw = xfer->rnw;265 266	xfer->cmd_tid = hci_get_tid();267 268	if (!rnw && data_len <= 4) {269		/* we use an Immediate Data Transfer Command */270		xfer->cmd_desc[0] =271			CMD_0_ATTR_I |272			CMD_I0_TID(xfer->cmd_tid) |273			CMD_I0_DEV_INDEX(dat_idx) |274			CMD_I0_DTT(data_len) |275			CMD_I0_MODE(mode);276		fill_data_bytes(xfer, data, data_len);277	} else {278		/* we use a Regular Data Transfer Command */279		xfer->cmd_desc[0] =280			CMD_0_ATTR_R |281			CMD_R0_TID(xfer->cmd_tid) |282			CMD_R0_DEV_INDEX(dat_idx) |283			CMD_R0_MODE(mode) |284			(rnw ? CMD_R0_RNW : 0);285		xfer->cmd_desc[1] =286			CMD_R1_DATA_LENGTH(data_len);287	}288}289 290static int hci_cmd_v1_daa(struct i3c_hci *hci)291{292	struct hci_xfer *xfer;293	int ret, dat_idx = -1;294	u8 next_addr = 0;295	u64 pid;296	unsigned int dcr, bcr;297	DECLARE_COMPLETION_ONSTACK(done);298 299	xfer = hci_alloc_xfer(1);300	if (!xfer)301		return -ENOMEM;302 303	/*304	 * Simple for now: we allocate a temporary DAT entry, do a single305	 * DAA, register the device which will allocate its own DAT entry306	 * via the core callback, then free the temporary DAT entry.307	 * Loop until there is no more devices to assign an address to.308	 * Yes, there is room for improvements.309	 */310	for (;;) {311		ret = mipi_i3c_hci_dat_v1.alloc_entry(hci);312		if (ret < 0)313			break;314		dat_idx = ret;315		ret = i3c_master_get_free_addr(&hci->master, next_addr);316		if (ret < 0)317			break;318		next_addr = ret;319 320		DBG("next_addr = 0x%02x, DAA using DAT %d", next_addr, dat_idx);321		mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, dat_idx, next_addr);322		mipi_i3c_hci_dct_index_reset(hci);323 324		xfer->cmd_tid = hci_get_tid();325		xfer->cmd_desc[0] =326			CMD_0_ATTR_A |327			CMD_A0_TID(xfer->cmd_tid) |328			CMD_A0_CMD(I3C_CCC_ENTDAA) |329			CMD_A0_DEV_INDEX(dat_idx) |330			CMD_A0_DEV_COUNT(1) |331			CMD_A0_ROC | CMD_A0_TOC;332		xfer->cmd_desc[1] = 0;333		xfer->completion = &done;334		hci->io->queue_xfer(hci, xfer, 1);335		if (!wait_for_completion_timeout(&done, HZ) &&336		    hci->io->dequeue_xfer(hci, xfer, 1)) {337			ret = -ETIME;338			break;339		}340		if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||341		     RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&342		    RESP_DATA_LENGTH(xfer->response) == 1) {343			ret = 0;  /* no more devices to be assigned */344			break;345		}346		if (RESP_STATUS(xfer->response) != RESP_SUCCESS) {347			ret = -EIO;348			break;349		}350 351		i3c_hci_dct_get_val(hci, 0, &pid, &dcr, &bcr);352		DBG("assigned address %#x to device PID=0x%llx DCR=%#x BCR=%#x",353		    next_addr, pid, dcr, bcr);354 355		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);356		dat_idx = -1;357 358		/*359		 * TODO: Extend the subsystem layer to allow for registering360		 * new device and provide BCR/DCR/PID at the same time.361		 */362		ret = i3c_master_add_i3c_dev_locked(&hci->master, next_addr);363		if (ret)364			break;365	}366 367	if (dat_idx >= 0)368		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);369	hci_free_xfer(xfer, 1);370	return ret;371}372 373const struct hci_cmd_ops mipi_i3c_hci_cmd_v1 = {374	.prep_ccc		= hci_cmd_v1_prep_ccc,375	.prep_i3c_xfer		= hci_cmd_v1_prep_i3c_xfer,376	.prep_i2c_xfer		= hci_cmd_v1_prep_i2c_xfer,377	.perform_daa		= hci_cmd_v1_daa,378};379