"Das U-Boot" Source Tree
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cmd: Add i3c command support.

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

Signed-off-by: Dinesh Maniyam <dinesh.maniyam@altera.com>

authored by

Dinesh Maniyam and committed by
Heiko Schocher
b875409d 82cc368c

+489 -2
+7
cmd/Kconfig
··· 1343 1343 help 1344 1344 I2C support. 1345 1345 1346 + config CMD_I3C 1347 + bool "i3c" 1348 + depends on I3C 1349 + help 1350 + Enable command to list i3c devices connected to the i3c controller 1351 + and perform read and write on the connected i3c devices. 1352 + 1346 1353 config CMD_W1 1347 1354 depends on W1 1348 1355 default y if W1
+1
cmd/Makefile
··· 95 95 obj-$(CONFIG_CMD_HISTORY) += history.o 96 96 obj-$(CONFIG_CMD_HVC) += smccc.o 97 97 obj-$(CONFIG_CMD_I2C) += i2c.o 98 + obj-$(CONFIG_CMD_I3C) += i3c.o 98 99 obj-$(CONFIG_CMD_IOTRACE) += iotrace.o 99 100 obj-$(CONFIG_CMD_HASH) += hash.o 100 101 obj-$(CONFIG_CMD_IDE) += ide.o disk.o
+271
cmd/i3c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (C) 2025 Altera Corporation <www.altera.com> 4 + */ 5 + 6 + #include <bootretry.h> 7 + #include <cli.h> 8 + #include <command.h> 9 + #include <console.h> 10 + #include <dm.h> 11 + #include <dw-i3c.h> 12 + #include <edid.h> 13 + #include <errno.h> 14 + #include <hexdump.h> 15 + #include <log.h> 16 + #include <malloc.h> 17 + #include <asm/byteorder.h> 18 + #include <linux/compiler.h> 19 + #include <linux/delay.h> 20 + #include <u-boot/crc.h> 21 + #include <linux/i3c/master.h> 22 + #include <linux/printk.h> 23 + #include <linux/types.h> 24 + 25 + static struct udevice *currdev; 26 + static struct udevice *prevdev; 27 + static struct dw_i3c_master *master; 28 + 29 + static void low_to_high_bytes(void *data, size_t size) 30 + { 31 + u8 *byte_data = data; 32 + size_t start = 0; 33 + size_t end = size - 1; 34 + 35 + while (start < end) { 36 + u8 temp = byte_data[start]; 37 + 38 + byte_data[start] = byte_data[end]; 39 + byte_data[end] = temp; 40 + start++; 41 + end--; 42 + } 43 + } 44 + 45 + static int handle_i3c_select(const char *name) 46 + { 47 + struct uclass *uc; 48 + struct udevice *dev_list; 49 + int ret = uclass_get_device_by_name(UCLASS_I3C, name, &currdev); 50 + 51 + if (ret) { 52 + currdev = prevdev; 53 + if (!currdev) { 54 + ret = uclass_get(UCLASS_I3C, &uc); 55 + if (ret) 56 + return CMD_RET_FAILURE; 57 + 58 + uclass_foreach_dev(dev_list, uc) 59 + printf("%s (%s)\n", dev_list->name, dev_list->driver->name); 60 + 61 + printf("i3c: Host controller not initialized: %s\n", name); 62 + return CMD_RET_FAILURE; 63 + } 64 + } else { 65 + master = dev_get_priv(currdev); 66 + printf("i3c: Current controller: %s\n", currdev->name); 67 + prevdev = currdev; 68 + } 69 + 70 + return CMD_RET_SUCCESS; 71 + } 72 + 73 + static int handle_i3c_list(void) 74 + { 75 + struct uclass *uc; 76 + struct udevice *dev_list; 77 + int ret = uclass_get(UCLASS_I3C, &uc); 78 + 79 + if (ret) 80 + return CMD_RET_FAILURE; 81 + 82 + uclass_foreach_dev(dev_list, uc) 83 + printf("%s (%s)\n", dev_list->name, dev_list->driver->name); 84 + 85 + return CMD_RET_SUCCESS; 86 + } 87 + 88 + static int handle_i3c_current(void) 89 + { 90 + if (!currdev) 91 + printf("i3c: No current controller selected\n"); 92 + else 93 + printf("i3c: Current controller: %s\n", currdev->name); 94 + 95 + return CMD_RET_SUCCESS; 96 + } 97 + 98 + static int handle_i3c_device_list(void) 99 + { 100 + if (!master) { 101 + printf("i3c: No controller active\n"); 102 + return CMD_RET_FAILURE; 103 + } 104 + 105 + for (int i = 0; i < master->num_i3cdevs; i++) { 106 + struct i3c_device_info *info = &master->i3cdev[i]->info; 107 + 108 + printf("Device %d:\n", i); 109 + printf(" Static Address : 0x%02X\n", info->static_addr); 110 + printf(" Dynamic Address : 0x%X\n", info->dyn_addr); 111 + printf(" PID : %016llx\n", info->pid); 112 + printf(" BCR : 0x%X\n", info->bcr); 113 + printf(" DCR : 0x%X\n", info->dcr); 114 + printf(" Max Read DS : 0x%X\n", info->max_read_ds); 115 + printf(" Max Write DS : 0x%X\n", info->max_write_ds); 116 + printf("\n"); 117 + } 118 + 119 + return CMD_RET_SUCCESS; 120 + } 121 + 122 + static int handle_i3c_write(int argc, char *const argv[]) 123 + { 124 + u32 mem_addr, num_bytes, dev_num_val; 125 + u8 device_num; 126 + u8 *data; 127 + int ret; 128 + 129 + if (argc < 5) 130 + return CMD_RET_USAGE; 131 + 132 + if (!currdev) { 133 + printf("i3c: No I3C controller selected\n"); 134 + return CMD_RET_FAILURE; 135 + } 136 + 137 + mem_addr = hextoul(argv[2], NULL); 138 + num_bytes = hextoul(argv[3], NULL); 139 + dev_num_val = hextoul(argv[4], NULL); 140 + 141 + if (num_bytes == 0 || num_bytes > 4) { 142 + printf("i3c: Length must be between 1 and 4\n"); 143 + return CMD_RET_USAGE; 144 + } 145 + 146 + if (dev_num_val > 0xFF) { 147 + printf("i3c: Device number 0x%x exceeds valid u8 range\n", dev_num_val); 148 + return CMD_RET_USAGE; 149 + } 150 + 151 + device_num = dev_num_val; 152 + data = malloc(num_bytes); 153 + 154 + if (!data) { 155 + printf("i3c: Memory allocation failed\n"); 156 + return -ENOMEM; 157 + } 158 + 159 + memcpy(data, (void *)(uintptr_t)mem_addr, num_bytes); 160 + low_to_high_bytes(data, num_bytes); 161 + 162 + ret = dm_i3c_write(currdev, device_num, data, num_bytes); 163 + 164 + if (ret) 165 + printf("i3c: Write failed: %d\n", ret); 166 + 167 + free(data); 168 + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; 169 + } 170 + 171 + static int handle_i3c_read(int argc, char *const argv[]) 172 + { 173 + u32 mem_addr, read_len, dev_num_val; 174 + u8 device_num; 175 + u8 *rdata; 176 + int ret; 177 + 178 + if (argc < 5) 179 + return CMD_RET_USAGE; 180 + 181 + if (!currdev) { 182 + printf("i3c: No I3C controller selected\n"); 183 + return CMD_RET_FAILURE; 184 + } 185 + 186 + mem_addr = hextoul(argv[2], NULL); 187 + read_len = hextoul(argv[3], NULL); 188 + dev_num_val = hextoul(argv[4], NULL); 189 + 190 + if (read_len == 0) { 191 + printf("i3c: Read length must be greater than 0\n"); 192 + return CMD_RET_USAGE; 193 + } 194 + 195 + if (dev_num_val > 0xFF) { 196 + printf("i3c: Device number 0x%x exceeds valid u8 range\n", dev_num_val); 197 + return CMD_RET_USAGE; 198 + } 199 + 200 + device_num = dev_num_val; 201 + rdata = malloc(read_len); 202 + 203 + if (!rdata) { 204 + printf("i3c: Memory allocation failed\n"); 205 + return -ENOMEM; 206 + } 207 + 208 + ret = dm_i3c_read(currdev, device_num, rdata, read_len); 209 + 210 + if (ret) { 211 + printf("i3c: Read failed: %d\n", ret); 212 + free(rdata); 213 + return CMD_RET_FAILURE; 214 + } 215 + 216 + memcpy((void *)(uintptr_t)mem_addr, rdata, read_len); 217 + print_hex_dump("i3c read: ", DUMP_PREFIX_OFFSET, 16, 1, 218 + (void *)(uintptr_t)mem_addr, read_len, false); 219 + 220 + free(rdata); 221 + return CMD_RET_SUCCESS; 222 + } 223 + 224 + static bool is_i3c_subcommand(const char *cmd) 225 + { 226 + return !strcmp(cmd, "write") || 227 + !strcmp(cmd, "read") || 228 + !strcmp(cmd, "device_list") || 229 + !strcmp(cmd, "list") || 230 + !strcmp(cmd, "current"); 231 + } 232 + 233 + static int do_i3c(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 234 + { 235 + if (argc < 2) 236 + return CMD_RET_USAGE; 237 + 238 + const char *subcmd = argv[1]; 239 + 240 + if (!is_i3c_subcommand(subcmd)) 241 + return handle_i3c_select(subcmd); 242 + 243 + if (!currdev) { 244 + printf("i3c: No I3C controller selected\n"); 245 + return CMD_RET_FAILURE; 246 + } 247 + 248 + if (!strcmp(subcmd, "list")) 249 + return handle_i3c_list(); 250 + else if (!strcmp(subcmd, "current")) 251 + return handle_i3c_current(); 252 + else if (!strcmp(subcmd, "device_list")) 253 + return handle_i3c_device_list(); 254 + else if (!strcmp(subcmd, "write")) 255 + return handle_i3c_write(argc, argv); 256 + else if (!strcmp(subcmd, "read")) 257 + return handle_i3c_read(argc, argv); 258 + 259 + return CMD_RET_USAGE; 260 + } 261 + 262 + U_BOOT_CMD( 263 + i3c, 5, 1, do_i3c, 264 + "access the system i3c", 265 + "i3c write <mem_addr> <length> <device_number> - write from memory to device\n" 266 + "i3c read <mem_addr> <length> <device_number> - read from device to memory\n" 267 + "i3c device_list - List valid target devices\n" 268 + "i3c <host_controller> - Select i3c controller\n" 269 + "i3c list - List all available i3c controllers\n" 270 + "i3c current - Show current i3c controller" 271 + );
+146
doc/usage/cmd/i3c.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + .. index:: 4 + single: i3c (command) 5 + 6 + i3c command 7 + =========== 8 + 9 + Synopsis 10 + -------- 11 + 12 + :: 13 + 14 + i3c <host_controller> 15 + i3c current 16 + i3c list 17 + i3c device_list 18 + i3c write <mem_addr> <length> <device_number> 19 + i3c read <mem_addr> <length> <device_number> 20 + 21 + Description 22 + ----------- 23 + 24 + The ``i3c`` command is used to probe the i3c host controller and perform 25 + read and write operations on the connected i3c devices. 26 + 27 + i3c current 28 + ------------ 29 + 30 + Display the currently selected i3c host controller. 31 + 32 + i3c list 33 + --------- 34 + 35 + List all the i3c hosts defined in the device-tree. 36 + 37 + i3c device_list 38 + ---------------- 39 + 40 + List all the i3c devices' device number, static address, dynamic address, 41 + PID, BCR, DCR, Max Write Speed, and Max Read Speed of the probed i3c host 42 + controller. 43 + 44 + i3c write 45 + ---------- 46 + 47 + Perform a write operation from memory to the connected i3c device. The data 48 + is read from a specified memory address and written to the selected i3c 49 + device, which is identified by its device number. 50 + 51 + You need to provide the memory address (``mem_addr``), the length of data 52 + to be written (``length``), and the device number (``device_number``). The 53 + data in memory will be transferred to the device in the specified order. 54 + 55 + i3c read 56 + --------- 57 + 58 + Perform a read operation from the connected i3c device to memory. The data 59 + is read from the selected i3c device and stored at the specified memory 60 + address. You need to provide the memory address (``mem_addr``), the length 61 + of data to be read (``length``), and the device number (``device_number``). 62 + 63 + The device will send the requested data, which is then written to the memory 64 + location you specified. This operation allows you to retrieve information 65 + from the device and use it in your application. The data is read in the 66 + order specified and can be multiple bytes. 67 + 68 + host_controller 69 + The name of the i3c host controller defined in the device-tree. 70 + 71 + length 72 + The size of the data to be read or written. 73 + 74 + device_number 75 + The device number in the driver model of the device connected to the i3c 76 + host controller. 77 + 78 + mem_addr 79 + The start address in memory from which to read or write the data. 80 + 81 + Examples 82 + -------- 83 + 84 + Probe the ``i3c0`` controller:: 85 + 86 + => i3c i3c0 87 + 88 + Display the current i3c host controller:: 89 + 90 + => i3c current 91 + 92 + Check the device number and PID of the connected devices:: 93 + 94 + => i3c device_list 95 + 96 + Perform write operations on the connected i3c device (device 0) from memory:: 97 + 98 + => i3c write 0x1000 4 0 99 + 100 + This command reads 4 bytes of data from memory starting at address 101 + ``0x1000`` and writes them to device 0, which is identified by its device 102 + number in the driver model. Example data from memory could look like this: 103 + 104 + ``` 105 + Data at 0x1000: 0xAA 0xBB 0xCC 0xDD 106 + ``` 107 + 108 + The bytes `0xAA`, `0xBB`, `0xCC`, and `0xDD` will be written to device 0. 109 + 110 + Perform a read operation from device 0 to memory (multiple bytes):: 111 + 112 + => i3c read 0x1000 4 0 113 + 114 + This command reads 4 bytes of data from device 0 and writes them to 115 + memory starting at address ``0x1000``. 116 + 117 + Example output after reading 4 bytes from device 0: 118 + 119 + ``` 120 + i3c Read: 121 + 00000000 AA BB CC DD 122 + ``` 123 + 124 + The bytes `0xAA`, `0xBB`, `0xCC`, and `0xDD` are read from device 0 125 + and written to memory at address `0x1000`. 126 + 127 + Configuration 128 + ------------- 129 + 130 + The ``i3c`` command is only available if CONFIG_CMD_I3C=y. 131 + 132 + Return value 133 + ------------ 134 + 135 + If the command succeeds, the return value ``$?`` is set to 0. If an error 136 + occurs, the return value ``$?`` is set to 1. 137 + 138 + Note 139 + ---- 140 + 141 + When specifying the data to be written to the i3c device (for example, with 142 + the ``i3c write`` command), the data can be provided in either uppercase 143 + or lowercase hexadecimal format. Both are valid and will be processed 144 + correctly. Similarly, when reading data with ``i3c read``, the data will be 145 + retrieved in the specified length and can include multiple bytes, all 146 + formatted in the same way.
+1
doc/usage/index.rst
··· 82 82 cmd/if 83 83 cmd/itest 84 84 cmd/imxtract 85 + cmd/i3c 85 86 cmd/load 86 87 cmd/loadb 87 88 cmd/loadm
+34 -1
drivers/i3c/master/dw-i3c-master.c
··· 674 674 newdevs &= ~olddevs; 675 675 676 676 for (pos = 0; pos < master->maxdevs; pos++) { 677 - if (newdevs & BIT(pos)) 677 + if (newdevs & BIT(pos)) { 678 678 i3c_master_add_i3c_dev_locked(m, master->addrs[pos]); 679 + master->i3cdev[pos] = m->this; 680 + master->num_i3cdevs++; 681 + } 679 682 } 680 683 681 684 dw_i3c_master_free_xfer(xfer); ··· 1010 1013 return ret; 1011 1014 } 1012 1015 1016 + static int dw_i3c_master_priv_read(struct udevice *dev, u32 dev_number, 1017 + u8 *buf, u32 buf_size) 1018 + { 1019 + struct dw_i3c_master *master = dev_get_priv(dev); 1020 + struct i3c_dev_desc *i3cdev = master->i3cdev[dev_number]; 1021 + struct i3c_priv_xfer i3c_xfers; 1022 + 1023 + i3c_xfers.data.in = buf; 1024 + i3c_xfers.len = buf_size; 1025 + i3c_xfers.rnw = I3C_MSG_READ; 1026 + 1027 + return dw_i3c_master_priv_xfers(i3cdev, &i3c_xfers, 1); 1028 + } 1029 + 1030 + static int dw_i3c_master_priv_write(struct udevice *dev, u32 dev_number, 1031 + u8 *buf, u32 buf_size) 1032 + { 1033 + struct dw_i3c_master *master = dev_get_priv(dev); 1034 + struct i3c_dev_desc *i3cdev = master->i3cdev[dev_number]; 1035 + struct i3c_priv_xfer i3c_xfers; 1036 + 1037 + i3c_xfers.data.out = buf; 1038 + i3c_xfers.len = buf_size; 1039 + i3c_xfers.rnw = I3C_MSG_WRITE; 1040 + 1041 + return dw_i3c_master_priv_xfers(i3cdev, &i3c_xfers, 1); 1042 + } 1043 + 1013 1044 static const struct dm_i3c_ops dw_i3c_ops = { 1014 1045 .i3c_xfers = dw_i3c_master_priv_xfers, 1046 + .read = dw_i3c_master_priv_read, 1047 + .write = dw_i3c_master_priv_write, 1015 1048 }; 1016 1049 1017 1050 static const struct udevice_id dw_i3c_ids[] = {
+2
include/dw-i3c.h
··· 241 241 char type[5]; 242 242 u8 addrs[MAX_DEVS]; 243 243 bool first_broadcast; 244 + struct i3c_dev_desc *i3cdev[I3C_BUS_MAX_DEVS]; 245 + u16 num_i3cdevs; 244 246 }; 245 247 246 248 struct dw_i3c_i2c_dev_data {
+27 -1
include/i3c.h
··· 25 25 int (*i3c_xfers)(struct i3c_dev_desc *dev, 26 26 struct i3c_priv_xfer *xfers, 27 27 u32 nxfers); 28 + 29 + /** 30 + * @read: Perform I3C read transaction. 31 + * 32 + * @dev: Chip to read from 33 + * @dev_number: The target device number from the driver model. 34 + * @buf: Place to put data 35 + * @num_bytes: Number of bytes to read. 36 + * 37 + * Return: 0 on success, negative error code on failure. 38 + */ 39 + int (*read)(struct udevice *dev, u32 dev_number, 40 + u8 *buf, u32 num_bytes); 41 + 42 + /** 43 + * @write: Perform I3C write transaction. 44 + * 45 + * @dev: Chip to write to 46 + * @dev_number: The target device number from the driver model. 47 + * @buf: Buffer containing data to write 48 + * @num_bytes: Number of bytes to write. 49 + * 50 + * Return: 0 on success, negative error code on failure. 51 + */ 52 + int (*write)(struct udevice *dev, u32 dev_number, 53 + u8 *buf, u32 num_bytes); 28 54 }; 29 55 30 56 /** ··· 64 90 * Return: 0 on success, negative error code on failure. 65 91 */ 66 92 int dm_i3c_read(struct udevice *dev, u32 dev_number, 67 - u8 *buf, u32 num_bytes); 93 + u8 *buf, u32 num_bytes);