[PATCH 09/10] cmd: Add i3c command support.

dinesh.maniyam at intel.com dinesh.maniyam at intel.com
Tue Feb 18 03:57:04 CET 2025


From: Dinesh Maniyam <dinesh.maniyam at intel.com>

Add i3c command file to support select, get i3c device
target list, read and write operation.

Signed-off-by: Dinesh Maniyam <dinesh.maniyam at intel.com>
---
 cmd/i3c.c                          | 193 +++++++++++++++++++++++++++++
 drivers/i3c/master/dw-i3c-master.c |  35 +++++-
 include/dw-i3c.h                   |   2 +
 include/i3c.h                      |   4 +
 4 files changed, 233 insertions(+), 1 deletion(-)
 create mode 100644 cmd/i3c.c

diff --git a/cmd/i3c.c b/cmd/i3c.c
new file mode 100644
index 0000000000..5631f487cc
--- /dev/null
+++ b/cmd/i3c.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Intel Coporation.
+ */
+
+#include <bootretry.h>
+#include <cli.h>
+#include <command.h>
+#include <console.h>
+#include <dm.h>
+#include <dw-i3c.h>
+#include <edid.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <u-boot/crc.h>
+#include <linux/i3c/master.h>
+
+static struct udevice *currdev;
+static struct udevice *prevdev;
+static struct dw_i3c_master *master;
+
+void low_to_high_bytes(void *data, size_t size)
+{
+	unsigned char *byte_data = (unsigned char *)data;
+	size_t start = 0;
+	size_t end = size - 1;
+
+	while (start < end) {
+		unsigned char temp = byte_data[start];
+
+		byte_data[start] = byte_data[end];
+		byte_data[end] = temp;
+		start++;
+		end--;
+	}
+}
+
+/**
+ * do_i3c() - Handle the "i3c" command-line command
+ * @cmdtp:    Command data struct pointer
+ * @flag:    Command flag
+ * @argc:    Command-line argument count
+ * @argv:    Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
+static int do_i3c(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct uclass *uc;
+	int ret;
+	struct udevice *dev_list;
+	u32 length, bytes;
+	u8 *data;
+	u8 *rdata;
+	u8 device_num;
+
+	if (argc > 1) {
+		ret = uclass_get_device_by_name(UCLASS_I3C, argv[1], &currdev);
+		if (ret) {
+			if (!strcmp(argv[1], "help"))
+				return CMD_RET_USAGE;
+
+			currdev = prevdev;
+			if (!currdev) {
+				ret = uclass_get(UCLASS_I3C, &uc);
+				if (ret)
+					return CMD_RET_FAILURE;
+
+				uclass_foreach_dev(dev_list, uc)
+					printf("%s (%s)\n", dev_list->name, dev_list->driver->name);
+
+				printf("i3c master controller is not initialized: %s\n", argv[1]);
+				return CMD_RET_FAILURE;
+			}
+		} else {
+			master = dev_get_priv(currdev);
+			printf("current dev: %s\n", currdev->name);
+			prevdev = currdev;
+		}
+	} else {
+		if (!currdev) {
+			printf("No i3c device set!\n");
+			return CMD_RET_FAILURE;
+		}
+		printf("dev: %s\n", currdev->name);
+	}
+
+	if (!strcmp(argv[1], "list")) {
+		ret = uclass_get(UCLASS_I3C, &uc);
+		if (ret)
+			return CMD_RET_FAILURE;
+
+		uclass_foreach_dev(dev_list, uc)
+		printf("%s (%s)\n", dev_list->name, dev_list->driver->name);
+	}
+
+	if (!strcmp(argv[1], "current")) {
+		if (!currdev)
+			printf("no current dev!\n");
+		else
+			printf("current dev: %s\n", currdev->name);
+	}
+
+	if ((!strcmp(argv[1], "write")) && !(argv[2] == NULL) && !(argv[3] == NULL) &&
+	    !(argv[4] == NULL)) {
+		length = hextoul(argv[3], NULL);
+
+		data = (u8 *)malloc(sizeof(u8) * length);
+		if (!data) {
+			debug("Memory allocation for data failed\n");
+			return -ENOMEM;
+		}
+
+		device_num = hextoul(argv[4], NULL);
+		bytes = hextoul(argv[2], NULL);
+
+		for (int i = 0; i < length; i++)
+			data[i] = (u8)((bytes >> (8 * i)) & 0xFF);
+
+		low_to_high_bytes(data, length);
+		ret = dm_i3c_write(currdev, device_num, data, length);
+		if (ret) {
+			ret = CMD_RET_FAILURE;
+			goto write_out;
+		}
+	}
+
+	if (!strcmp(argv[1], "read") && !(argv[2] == NULL) && !(argv[3] == NULL)) {
+		length = hextoul(argv[2], NULL);
+
+		rdata = (u8 *) malloc(sizeof(u8) * length);
+		if (!rdata) {
+			debug("Memory allocation for rdata failed\n");
+			return -ENOMEM;
+		}
+
+		device_num = hextoul(argv[3], NULL);
+
+		ret = dm_i3c_read(currdev, device_num, rdata, length);
+		if (ret) {
+			ret =  CMD_RET_FAILURE;
+		} else {
+			printf("Read buff: ");
+			for (size_t i = 0; i < length; ++i)
+				printf("%02x", rdata[i]);
+
+			printf("\n");
+		}
+
+		goto read_out;
+	}
+
+	if (!strcmp(argv[1], "device_list")) {
+		if (master) {
+			for (int i = 0; i < master->num_i3cdevs; i++) {
+				printf("device:%d\n", i);
+				printf("dynamic address:0x%X\n", master->i3cdev[i]->info.dyn_addr);
+				printf("PID:%llx\n", master->i3cdev[i]->info.pid);
+				printf("BCR:%X\n", master->i3cdev[i]->info.bcr);
+				printf("DCR:%X\n", master->i3cdev[i]->info.dcr);
+				printf("Max Read DS:%X\n", master->i3cdev[i]->info.max_read_ds);
+				printf("Max Write DS:%X\n", master->i3cdev[i]->info.max_write_ds);
+				printf("\n");
+			}
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+
+read_out:
+	free(rdata);
+	return ret;
+
+write_out:
+	free(data);
+	return ret;
+}
+
+U_BOOT_CMD(
+	i3c,    5,    1,     do_i3c,
+	"access the system i3c\n",
+	"i3c write<data><length><device_number> - write to device.\n"
+	"i3c read<length><device_number> - read from device.\n"
+	"i3c device_list   - List valid target devices\n"
+	"i3c <i3c name>   - Select i3c controller.\n"
+	"i3c list   - List all the available i3c controller.\n"
+	"i3c current   - print current i3c controller.\n"
+);
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index af6e472f23..98bf894701 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -670,8 +670,11 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 	newdevs &= ~olddevs;
 
 	for (pos = 0; pos < master->maxdevs; pos++) {
-		if (newdevs & BIT(pos))
+		if (newdevs & BIT(pos)) {
 			i3c_master_add_i3c_dev_locked(m, master->addrs[pos]);
+			master->i3cdev[pos] = m->this;
+			master->num_i3cdevs++;
+		}
 	}
 
 	dw_i3c_master_free_xfer(xfer);
@@ -1006,8 +1009,38 @@ err_assert_rst:
 	return ret;
 }
 
+static int dw_i3c_master_priv_read(struct udevice *dev, u8 dev_number,
+				   u8 *buf, int buf_size)
+{
+	struct dw_i3c_master *master = dev_get_priv(dev);
+	struct i3c_dev_desc *i3cdev = master->i3cdev[dev_number];
+	struct i3c_priv_xfer i3c_xfers;
+
+	i3c_xfers.data.in = buf;
+	i3c_xfers.len = buf_size;
+	i3c_xfers.rnw = I3C_MSG_READ;
+
+	return dw_i3c_master_priv_xfers(i3cdev, &i3c_xfers, 1);
+}
+
+static int dw_i3c_master_priv_write(struct udevice *dev, u8 dev_number,
+				    u8 *buf, int buf_size)
+{
+	struct dw_i3c_master *master = dev_get_priv(dev);
+	struct i3c_dev_desc *i3cdev = master->i3cdev[dev_number];
+	struct i3c_priv_xfer i3c_xfers;
+
+	i3c_xfers.data.out = buf;
+	i3c_xfers.len = buf_size;
+	i3c_xfers.rnw = I3C_MSG_WRITE;
+
+	return dw_i3c_master_priv_xfers(i3cdev, &i3c_xfers, 1);
+}
+
 static const struct dm_i3c_ops dw_i3c_ops = {
 	.i3c_xfers = dw_i3c_master_priv_xfers,
+	.read = dw_i3c_master_priv_read,
+	.write = dw_i3c_master_priv_write,
 };
 
 static const struct udevice_id dw_i3c_ids[] = {
diff --git a/include/dw-i3c.h b/include/dw-i3c.h
index 42c37d6dfa..c652de7740 100644
--- a/include/dw-i3c.h
+++ b/include/dw-i3c.h
@@ -241,6 +241,8 @@ struct dw_i3c_master {
 	char type[5];
 	u8 addrs[MAX_DEVS];
 	bool first_broadcast;
+	struct i3c_dev_desc *i3cdev[I3C_BUS_MAX_DEVS];
+	u16 num_i3cdevs;
 };
 
 struct dw_i3c_i2c_dev_data {
diff --git a/include/i3c.h b/include/i3c.h
index 6ef4982dcf..969753ae49 100644
--- a/include/i3c.h
+++ b/include/i3c.h
@@ -28,6 +28,10 @@ struct dm_i3c_ops {
 	int (*i3c_xfers)(struct i3c_dev_desc *dev,
 			 struct i3c_priv_xfer *i3c_xfers,
 			 int i3c_nxfers);
+	int (*read)(struct udevice *dev, u8 dev_number,
+		    u8 *buf, int num_bytes);
+	int (*write)(struct udevice *dev, u8 dev_number,
+		     u8 *buf, int num_bytes);
 };
 
 #define i3c_get_ops(dev)	((struct dm_i3c_ops *)(dev)->driver->ops)
-- 
2.26.2



More information about the U-Boot mailing list