diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/Kconfig | 7 | ||||
-rw-r--r-- | cmd/Makefile | 1 | ||||
-rw-r--r-- | cmd/i2c.c | 3 | ||||
-rw-r--r-- | cmd/i3c.c | 271 | ||||
-rw-r--r-- | cmd/meminfo.c | 2 |
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; } |