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