"Das U-Boot" Source Tree
at master 355 lines 7.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2016 4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 5 * 6 * (C) Copyright 2017, 2018 7 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12#include <axi.h> 13#include <command.h> 14#include <console.h> 15#include <display_options.h> 16#include <dm.h> 17#include <log.h> 18 19/* Currently selected AXI bus device */ 20static struct udevice *axi_cur_bus; 21/* Transmission size from last command */ 22static uint dp_last_size; 23/* Address from last command */ 24static uint dp_last_addr; 25/* Number of bytes to display from last command; default = 64 */ 26static uint dp_last_length = 0x40; 27 28/** 29 * show_bus() - Show devices on a single AXI bus 30 * @bus: The AXI bus device to printt information for 31 */ 32static void show_bus(struct udevice *bus) 33{ 34 struct udevice *dev; 35 36 printf("Bus %d:\t%s", dev_seq(bus), bus->name); 37 if (device_active(bus)) 38 printf(" (active)"); 39 printf("\n"); 40 for (device_find_first_child(bus, &dev); 41 dev; 42 device_find_next_child(&dev)) 43 printf(" %s\n", dev->name); 44} 45 46/** 47 * axi_set_cur_bus() - Set the currently active AXI bus 48 * @busnum: The number of the bus (i.e. its sequence number) that should be 49 * made active 50 * 51 * The operations supplied by this command operate only on the currently active 52 * bus. 53 * 54 * Return: 0 if OK, -ve on error 55 */ 56static int axi_set_cur_bus(unsigned int busnum) 57{ 58 struct udevice *bus; 59 struct udevice *dummy; 60 int ret; 61 62 /* Make sure that all sequence numbers are initialized */ 63 for (uclass_first_device(UCLASS_AXI, &dummy); 64 dummy; 65 uclass_next_device(&dummy)) 66 ; 67 68 ret = uclass_get_device_by_seq(UCLASS_AXI, busnum, &bus); 69 if (ret) { 70 debug("%s: No bus %d\n", __func__, busnum); 71 return ret; 72 } 73 axi_cur_bus = bus; 74 75 return 0; 76} 77 78/** 79 * axi_get_cur_bus() - Retrieve the currently active AXI bus device 80 * @busp: Pointer to a struct udevice that receives the currently active bus 81 * device 82 * 83 * Return: 0 if OK, -ve on error 84 */ 85static int axi_get_cur_bus(struct udevice **busp) 86{ 87 if (!axi_cur_bus) { 88 puts("No AXI bus selected\n"); 89 return -ENODEV; 90 } 91 *busp = axi_cur_bus; 92 93 return 0; 94} 95 96/* 97 * Command handlers 98 */ 99 100static int do_axi_show_bus(struct cmd_tbl *cmdtp, int flag, int argc, 101 char *const argv[]) 102{ 103 struct udevice *dummy; 104 105 /* Make sure that all sequence numbers are initialized */ 106 for (uclass_first_device(UCLASS_AXI, &dummy); 107 dummy; 108 uclass_next_device(&dummy)) 109 ; 110 111 if (argc == 1) { 112 /* show all busses */ 113 struct udevice *bus; 114 115 for (uclass_first_device(UCLASS_AXI, &bus); 116 bus; 117 uclass_next_device(&bus)) 118 show_bus(bus); 119 } else { 120 int i; 121 122 /* show specific bus */ 123 i = dectoul(argv[1], NULL); 124 125 struct udevice *bus; 126 int ret; 127 128 ret = uclass_get_device_by_seq(UCLASS_AXI, i, &bus); 129 if (ret) { 130 printf("Invalid bus %d: err=%d\n", i, ret); 131 return CMD_RET_FAILURE; 132 } 133 show_bus(bus); 134 } 135 136 return 0; 137} 138 139static int do_axi_bus_num(struct cmd_tbl *cmdtp, int flag, int argc, 140 char *const argv[]) 141{ 142 int ret = 0; 143 int bus_no; 144 145 if (argc == 1) { 146 /* querying current setting */ 147 struct udevice *bus; 148 149 if (!axi_get_cur_bus(&bus)) 150 bus_no = dev_seq(bus); 151 else 152 bus_no = -1; 153 154 printf("Current bus is %d\n", bus_no); 155 } else { 156 bus_no = dectoul(argv[1], NULL); 157 printf("Setting bus to %d\n", bus_no); 158 159 ret = axi_set_cur_bus(bus_no); 160 if (ret) 161 printf("Failure changing bus number (%d)\n", ret); 162 } 163 164 return ret ? CMD_RET_FAILURE : 0; 165} 166 167static int do_axi_md(struct cmd_tbl *cmdtp, int flag, int argc, 168 char *const argv[]) 169{ 170 /* Print that many bytes per line */ 171 const uint DISP_LINE_LEN = 16; 172 u8 linebuf[DISP_LINE_LEN]; 173 unsigned int k; 174 ulong addr, length, size; 175 ulong nbytes; 176 enum axi_size_t axisize; 177 int unitsize; 178 179 /* 180 * We use the last specified parameters, unless new ones are 181 * entered. 182 */ 183 size = dp_last_size; 184 addr = dp_last_addr; 185 length = dp_last_length; 186 187 if (argc < 3) 188 return CMD_RET_USAGE; 189 190 if (!axi_cur_bus) { 191 puts("No AXI bus selected\n"); 192 return CMD_RET_FAILURE; 193 } 194 195 if ((flag & CMD_FLAG_REPEAT) == 0) { 196 size = dectoul(argv[1], NULL); 197 198 /* 199 * Address is specified since argc >= 3 200 */ 201 addr = hextoul(argv[2], NULL); 202 203 /* 204 * If there's another parameter, it is the length to display; 205 * length is the number of objects, not number of bytes 206 */ 207 if (argc > 3) 208 length = hextoul(argv[3], NULL); 209 } 210 211 switch (size) { 212 case 8: 213 axisize = AXI_SIZE_8; 214 unitsize = 1; 215 break; 216 case 16: 217 axisize = AXI_SIZE_16; 218 unitsize = 2; 219 break; 220 case 32: 221 axisize = AXI_SIZE_32; 222 unitsize = 4; 223 break; 224 default: 225 printf("Unknown read size '%lu'\n", size); 226 return CMD_RET_USAGE; 227 }; 228 229 nbytes = length * unitsize; 230 do { 231 ulong linebytes = (nbytes > DISP_LINE_LEN) ? 232 DISP_LINE_LEN : nbytes; 233 234 for (k = 0; k < linebytes / unitsize; ++k) { 235 int ret = axi_read(axi_cur_bus, addr + k * unitsize, 236 linebuf + k * unitsize, axisize); 237 238 if (!ret) /* Continue if axi_read was successful */ 239 continue; 240 241 if (ret == -ENOSYS) 242 printf("axi_read failed; read size not supported?\n"); 243 else 244 printf("axi_read failed: err = %d\n", ret); 245 246 return CMD_RET_FAILURE; 247 } 248 print_buffer(addr, (void *)linebuf, unitsize, 249 linebytes / unitsize, 250 DISP_LINE_LEN / unitsize); 251 252 nbytes -= max(linebytes, 1UL); 253 addr += linebytes; 254 255 if (ctrlc()) 256 break; 257 } while (nbytes > 0); 258 259 dp_last_size = size; 260 dp_last_addr = addr; 261 dp_last_length = length; 262 263 return 0; 264} 265 266static int do_axi_mw(struct cmd_tbl *cmdtp, int flag, int argc, 267 char *const argv[]) 268{ 269 u32 writeval; 270 ulong addr, count, size; 271 enum axi_size_t axisize; 272 273 if (argc <= 3 || argc >= 6) 274 return CMD_RET_USAGE; 275 276 size = dectoul(argv[1], NULL); 277 278 switch (size) { 279 case 8: 280 axisize = AXI_SIZE_8; 281 break; 282 case 16: 283 axisize = AXI_SIZE_16; 284 break; 285 case 32: 286 axisize = AXI_SIZE_32; 287 break; 288 default: 289 printf("Unknown write size '%lu'\n", size); 290 return CMD_RET_USAGE; 291 }; 292 293 /* Address is specified since argc > 4 */ 294 addr = hextoul(argv[2], NULL); 295 296 /* Get the value to write */ 297 writeval = hextoul(argv[3], NULL); 298 299 /* Count ? */ 300 if (argc == 5) 301 count = hextoul(argv[4], NULL); 302 else 303 count = 1; 304 305 while (count-- > 0) { 306 int ret = axi_write(axi_cur_bus, addr + count * sizeof(u32), 307 &writeval, axisize); 308 309 if (ret) { 310 printf("axi_write failed: err = %d\n", ret); 311 return CMD_RET_FAILURE; 312 } 313 } 314 315 return 0; 316} 317 318static struct cmd_tbl cmd_axi_sub[] = { 319 U_BOOT_CMD_MKENT(bus, 1, 1, do_axi_show_bus, "", ""), 320 U_BOOT_CMD_MKENT(dev, 1, 1, do_axi_bus_num, "", ""), 321 U_BOOT_CMD_MKENT(md, 4, 1, do_axi_md, "", ""), 322 U_BOOT_CMD_MKENT(mw, 5, 1, do_axi_mw, "", ""), 323}; 324 325static int do_ihs_axi(struct cmd_tbl *cmdtp, int flag, int argc, 326 char *const argv[]) 327{ 328 struct cmd_tbl *c; 329 330 if (argc < 2) 331 return CMD_RET_USAGE; 332 333 /* Strip off leading 'axi' command argument */ 334 argc--; 335 argv++; 336 337 /* Hand off rest of command line to sub-commands */ 338 c = find_cmd_tbl(argv[0], &cmd_axi_sub[0], ARRAY_SIZE(cmd_axi_sub)); 339 340 if (c) 341 return c->cmd(cmdtp, flag, argc, argv); 342 else 343 return CMD_RET_USAGE; 344} 345 346U_BOOT_LONGHELP(axi, 347 "bus - show AXI bus info\n" 348 "axi dev [bus] - show or set current AXI bus to bus number [bus]\n" 349 "axi md size addr [# of objects] - read from AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n" 350 "axi mw size addr value [count] - write data [value] to AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n"); 351 352U_BOOT_CMD(axi, 7, 1, do_ihs_axi, 353 "AXI sub-system", 354 axi_help_text 355);