summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/Kconfig7
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/i2c.c3
-rw-r--r--cmd/i3c.c271
-rw-r--r--cmd/meminfo.c2
5 files changed, 282 insertions, 2 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig
index b3b5be1ea79..1a7dba2a27d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1343,6 +1343,13 @@ config CMD_I2C
help
I2C support.
+config CMD_I3C
+ bool "i3c"
+ depends on I3C
+ help
+ Enable command to list i3c devices connected to the i3c controller
+ and perform read and write on the connected i3c devices.
+
config CMD_W1
depends on W1
default y if W1
diff --git a/cmd/Makefile b/cmd/Makefile
index 12e948fd1b9..36e79cc3c28 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CMD_GPIO) += gpio.o
obj-$(CONFIG_CMD_HISTORY) += history.o
obj-$(CONFIG_CMD_HVC) += smccc.o
obj-$(CONFIG_CMD_I2C) += i2c.o
+obj-$(CONFIG_CMD_I3C) += i3c.o
obj-$(CONFIG_CMD_IOTRACE) += iotrace.o
obj-$(CONFIG_CMD_HASH) += hash.o
obj-$(CONFIG_CMD_IDE) += ide.o disk.o
diff --git a/cmd/i2c.c b/cmd/i2c.c
index f0aae93073f..e021067e68a 100644
--- a/cmd/i2c.c
+++ b/cmd/i2c.c
@@ -299,7 +299,8 @@ static int do_i2c_write(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
uint chip;
- uint devaddr, length;
+ uint devaddr;
+ int length;
int alen;
u_char *memaddr;
int ret;
diff --git a/cmd/i3c.c b/cmd/i3c.c
new file mode 100644
index 00000000000..08957f4d447
--- /dev/null
+++ b/cmd/i3c.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#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 <hexdump.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>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+static struct udevice *currdev;
+static struct udevice *prevdev;
+static struct dw_i3c_master *master;
+
+static void low_to_high_bytes(void *data, size_t size)
+{
+ u8 *byte_data = data;
+ size_t start = 0;
+ size_t end = size - 1;
+
+ while (start < end) {
+ u8 temp = byte_data[start];
+
+ byte_data[start] = byte_data[end];
+ byte_data[end] = temp;
+ start++;
+ end--;
+ }
+}
+
+static int handle_i3c_select(const char *name)
+{
+ struct uclass *uc;
+ struct udevice *dev_list;
+ int ret = uclass_get_device_by_name(UCLASS_I3C, name, &currdev);
+
+ if (ret) {
+ 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: Host controller not initialized: %s\n", name);
+ return CMD_RET_FAILURE;
+ }
+ } else {
+ master = dev_get_priv(currdev);
+ printf("i3c: Current controller: %s\n", currdev->name);
+ prevdev = currdev;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int handle_i3c_list(void)
+{
+ struct uclass *uc;
+ struct udevice *dev_list;
+ int 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);
+
+ return CMD_RET_SUCCESS;
+}
+
+static int handle_i3c_current(void)
+{
+ if (!currdev)
+ printf("i3c: No current controller selected\n");
+ else
+ printf("i3c: Current controller: %s\n", currdev->name);
+
+ return CMD_RET_SUCCESS;
+}
+
+static int handle_i3c_device_list(void)
+{
+ if (!master) {
+ printf("i3c: No controller active\n");
+ return CMD_RET_FAILURE;
+ }
+
+ for (int i = 0; i < master->num_i3cdevs; i++) {
+ struct i3c_device_info *info = &master->i3cdev[i]->info;
+
+ printf("Device %d:\n", i);
+ printf(" Static Address : 0x%02X\n", info->static_addr);
+ printf(" Dynamic Address : 0x%X\n", info->dyn_addr);
+ printf(" PID : %016llx\n", info->pid);
+ printf(" BCR : 0x%X\n", info->bcr);
+ printf(" DCR : 0x%X\n", info->dcr);
+ printf(" Max Read DS : 0x%X\n", info->max_read_ds);
+ printf(" Max Write DS : 0x%X\n", info->max_write_ds);
+ printf("\n");
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int handle_i3c_write(int argc, char *const argv[])
+{
+ u32 mem_addr, num_bytes, dev_num_val;
+ u8 device_num;
+ u8 *data;
+ int ret;
+
+ if (argc < 5)
+ return CMD_RET_USAGE;
+
+ if (!currdev) {
+ printf("i3c: No I3C controller selected\n");
+ return CMD_RET_FAILURE;
+ }
+
+ mem_addr = hextoul(argv[2], NULL);
+ num_bytes = hextoul(argv[3], NULL);
+ dev_num_val = hextoul(argv[4], NULL);
+
+ if (num_bytes == 0 || num_bytes > 4) {
+ printf("i3c: Length must be between 1 and 4\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (dev_num_val > 0xFF) {
+ printf("i3c: Device number 0x%x exceeds valid u8 range\n", dev_num_val);
+ return CMD_RET_USAGE;
+ }
+
+ device_num = dev_num_val;
+ data = malloc(num_bytes);
+
+ if (!data) {
+ printf("i3c: Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ memcpy(data, (void *)(uintptr_t)mem_addr, num_bytes);
+ low_to_high_bytes(data, num_bytes);
+
+ ret = dm_i3c_write(currdev, device_num, data, num_bytes);
+
+ if (ret)
+ printf("i3c: Write failed: %d\n", ret);
+
+ free(data);
+ return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int handle_i3c_read(int argc, char *const argv[])
+{
+ u32 mem_addr, read_len, dev_num_val;
+ u8 device_num;
+ u8 *rdata;
+ int ret;
+
+ if (argc < 5)
+ return CMD_RET_USAGE;
+
+ if (!currdev) {
+ printf("i3c: No I3C controller selected\n");
+ return CMD_RET_FAILURE;
+ }
+
+ mem_addr = hextoul(argv[2], NULL);
+ read_len = hextoul(argv[3], NULL);
+ dev_num_val = hextoul(argv[4], NULL);
+
+ if (read_len == 0) {
+ printf("i3c: Read length must be greater than 0\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (dev_num_val > 0xFF) {
+ printf("i3c: Device number 0x%x exceeds valid u8 range\n", dev_num_val);
+ return CMD_RET_USAGE;
+ }
+
+ device_num = dev_num_val;
+ rdata = malloc(read_len);
+
+ if (!rdata) {
+ printf("i3c: Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ ret = dm_i3c_read(currdev, device_num, rdata, read_len);
+
+ if (ret) {
+ printf("i3c: Read failed: %d\n", ret);
+ free(rdata);
+ return CMD_RET_FAILURE;
+ }
+
+ memcpy((void *)(uintptr_t)mem_addr, rdata, read_len);
+ print_hex_dump("i3c read: ", DUMP_PREFIX_OFFSET, 16, 1,
+ (void *)(uintptr_t)mem_addr, read_len, false);
+
+ free(rdata);
+ return CMD_RET_SUCCESS;
+}
+
+static bool is_i3c_subcommand(const char *cmd)
+{
+ return !strcmp(cmd, "write") ||
+ !strcmp(cmd, "read") ||
+ !strcmp(cmd, "device_list") ||
+ !strcmp(cmd, "list") ||
+ !strcmp(cmd, "current");
+}
+
+static int do_i3c(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ const char *subcmd = argv[1];
+
+ if (!is_i3c_subcommand(subcmd))
+ return handle_i3c_select(subcmd);
+
+ if (!currdev) {
+ printf("i3c: No I3C controller selected\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!strcmp(subcmd, "list"))
+ return handle_i3c_list();
+ else if (!strcmp(subcmd, "current"))
+ return handle_i3c_current();
+ else if (!strcmp(subcmd, "device_list"))
+ return handle_i3c_device_list();
+ else if (!strcmp(subcmd, "write"))
+ return handle_i3c_write(argc, argv);
+ else if (!strcmp(subcmd, "read"))
+ return handle_i3c_read(argc, argv);
+
+ return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+ i3c, 5, 1, do_i3c,
+ "access the system i3c",
+ "i3c write <mem_addr> <length> <device_number> - write from memory to device\n"
+ "i3c read <mem_addr> <length> <device_number> - read from device to memory\n"
+ "i3c device_list - List valid target devices\n"
+ "i3c <host_controller> - Select i3c controller\n"
+ "i3c list - List all available i3c controllers\n"
+ "i3c current - Show current i3c controller"
+);
diff --git a/cmd/meminfo.c b/cmd/meminfo.c
index acdb38dcba0..aa3b5bafe17 100644
--- a/cmd/meminfo.c
+++ b/cmd/meminfo.c
@@ -93,7 +93,7 @@ static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc,
print_region("stack", stk_bot, CONFIG_STACK_SIZE, &upto);
if (IS_ENABLED(CONFIG_LMB))
show_lmb(lmb_get(), &upto);
- print_region("free", gd->ram_base, upto, &upto);
+ print_region("free", gd->ram_base, upto - gd->ram_base, &upto);
return 0;
}