File Index
Files and directories
Sign in
FILE

cmd_v1.c

File preview with syntax highlighting.

linux-6.19.14/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c C
  1// SPDX-License-Identifier: BSD-3-Clause
  2/*
  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 Handling
  8 */
  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 Command
 21 */
 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 Command
 34 */
 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 Command
 55 */
 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) Command
 73 */
 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 Command
 93 */
 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 single
305	 * DAA, register the device which will allocate its own DAT entry
306	 * 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		dev_dbg(&hci->master.dev,
321			"next_addr = 0x%02x, DAA using DAT %d",
322			next_addr, dat_idx);
323		mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, dat_idx, next_addr);
324		mipi_i3c_hci_dct_index_reset(hci);
325
326		xfer->cmd_tid = hci_get_tid();
327		xfer->cmd_desc[0] =
328			CMD_0_ATTR_A |
329			CMD_A0_TID(xfer->cmd_tid) |
330			CMD_A0_CMD(I3C_CCC_ENTDAA) |
331			CMD_A0_DEV_INDEX(dat_idx) |
332			CMD_A0_DEV_COUNT(1) |
333			CMD_A0_ROC | CMD_A0_TOC;
334		xfer->cmd_desc[1] = 0;
335		xfer->completion = &done;
336		hci->io->queue_xfer(hci, xfer, 1);
337		if (!wait_for_completion_timeout(&done, HZ) &&
338		    hci->io->dequeue_xfer(hci, xfer, 1)) {
339			ret = -ETIMEDOUT;
340			break;
341		}
342		if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
343		     RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
344		    RESP_DATA_LENGTH(xfer->response) == 1) {
345			ret = 0;  /* no more devices to be assigned */
346			break;
347		}
348		if (RESP_STATUS(xfer->response) != RESP_SUCCESS) {
349			ret = -EIO;
350			break;
351		}
352
353		i3c_hci_dct_get_val(hci, 0, &pid, &dcr, &bcr);
354		dev_dbg(&hci->master.dev,
355			"assigned address %#x to device PID=0x%llx DCR=%#x BCR=%#x",
356			next_addr, pid, dcr, bcr);
357
358		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
359		dat_idx = -1;
360
361		/*
362		 * TODO: Extend the subsystem layer to allow for registering
363		 * new device and provide BCR/DCR/PID at the same time.
364		 */
365		ret = i3c_master_add_i3c_dev_locked(&hci->master, next_addr);
366		if (ret)
367			break;
368	}
369
370	if (dat_idx >= 0)
371		mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
372	hci_free_xfer(xfer, 1);
373	return ret;
374}
375
376const struct hci_cmd_ops mipi_i3c_hci_cmd_v1 = {
377	.prep_ccc		= hci_cmd_v1_prep_ccc,
378	.prep_i3c_xfer		= hci_cmd_v1_prep_i3c_xfer,
379	.prep_i2c_xfer		= hci_cmd_v1_prep_i2c_xfer,
380	.perform_daa		= hci_cmd_v1_daa,
381};
~/ Read-only file preview.