
Hi Simon,
On Wed, Jul 19, 2017 at 11:06 AM, Simon Glass sjg@chromium.org wrote:
On 14 July 2017 at 05:55, Mario Six mario.six@gdsys.cc wrote:
Add a command to debug the IHS AXI bus.
Signed-off-by: Mario Six mario.six@gdsys.cc
cmd/Kconfig | 5 ++ cmd/Makefile | 2 + cmd/ihs_axi.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 cmd/ihs_axi.c
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/cmd/Kconfig b/cmd/Kconfig index b632049022..4bbe9d435c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -753,6 +753,11 @@ config CMD_SATA Attachment, where AT refers to an IBM AT (Advanced Technology) computer released in 1984.
+config CMD_IHS_AXI
bool "axi"
help
Enable the GDSYS IHS AXI command for accessing the AXI bus.
Can we make this help generic?
depends on AXI
Will fix in v2. The AXI driver will have to become more general anyway, so adjusting the matching command is prudent as well.
endmenu
diff --git a/cmd/Makefile b/cmd/Makefile index c30511982b..0baaf76b47 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -144,6 +144,8 @@ obj-$(CONFIG_CMD_DFU) += dfu.o obj-$(CONFIG_CMD_GPT) += gpt.o obj-$(CONFIG_CMD_ETHSW) += ethsw.o
+obj-$(CONFIG_CMD_IHS_AXI) += ihs_axi.o
# Power obj-$(CONFIG_CMD_PMIC) += pmic.o obj-$(CONFIG_CMD_REGULATOR) += regulator.o diff --git a/cmd/ihs_axi.c b/cmd/ihs_axi.c new file mode 100644 index 0000000000..336c239fae --- /dev/null +++ b/cmd/ihs_axi.c @@ -0,0 +1,257 @@ +/*
- (C) Copyright 2016
- Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
- (C) Copyright 2017
- Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <command.h> +#include <console.h> +#include <ihs_axi.h>
+static struct udevice *axi_cur_bus; +static uint dp_last_addr; +static uint dp_last_length = 0x40;
+static void show_bus(struct udevice *bus) +{
struct udevice *dev;
printf("Bus %d:\t%s", bus->req_seq, bus->name);
if (device_active(bus))
printf(" (active %d)", bus->seq);
printf("\n");
for (device_find_first_child(bus, &dev);
dev;
device_find_next_child(&dev)) {
//struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
//printf(" %02x: %s, offset len %x, flags %x\n",
//chip->chip_addr, dev->name, chip->offset_len,
//chip->flags);
debug() ?
That's leftover development code, sorry. I'll move it to debug in v2.
printf(" %s\n", dev->name);
}
+}
+static int do_axi_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
if (argc == 1) {
/* show all busses */
struct udevice *bus;
struct uclass *uc;
int ret;
ret = uclass_get(UCLASS_IHS_AXI, &uc);
if (ret)
return CMD_RET_FAILURE;
uclass_foreach_dev(bus, uc)
show_bus(bus);
} else {
int i;
/* show specific bus */
i = simple_strtoul(argv[1], NULL, 10);
struct udevice *bus;
int ret;
ret = uclass_get_device_by_seq(UCLASS_IHS_AXI, i, &bus);
This is fine, but note that above you may be looking at buses that are not probed (since you use the find API). Here the device will be probed.
Ah, I see. I'll equalize the behavior in v2.
if (ret) {
printf("Invalid bus %d: err=%d\n", i, ret);
return CMD_RET_FAILURE;
}
show_bus(bus);
}
return 0;
+}
+static int cmd_axi_set_bus_num(unsigned int busnum) +{
struct udevice *bus;
int ret;
ret = uclass_get_device_by_seq(UCLASS_IHS_AXI, busnum, &bus);
if (ret) {
debug("%s: No bus %d\n", __func__, busnum);
return ret;
}
axi_cur_bus = bus;
return 0;
+}
+static int axi_get_cur_bus(struct udevice **busp) +{
if (!axi_cur_bus) {
puts("No AXI bus selected\n");
return ENODEV;
}
*busp = axi_cur_bus;
return 0;
+}
+static int do_axi_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
int ret = 0;
int bus_no;
if (argc == 1) {
/* querying current setting */
struct udevice *bus;
if (!axi_get_cur_bus(&bus))
bus_no = bus->seq;
else
bus_no = -1;
printf("Current bus is %d\n", bus_no);
} else {
bus_no = simple_strtoul(argv[1], NULL, 10);
printf("Setting bus to %d\n", bus_no);
ret = cmd_axi_set_bus_num(bus_no);
if (ret)
printf("Failure changing bus number (%d)\n", ret);
}
return ret ? CMD_RET_FAILURE : 0;
+}
+#define DISP_LINE_LEN 16
+int do_axi_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
unsigned int k;
ulong addr, length;
int rc = 0;
u32 linebuf[DISP_LINE_LEN / sizeof(u32)];
ulong nbytes;
/*
* We use the last specified parameters, unless new ones are
* entered.
*/
addr = dp_last_addr;
length = dp_last_length;
if (argc < 2)
return CMD_RET_USAGE;
if (!axi_cur_bus) {
puts("No AXI bus selected\n");
return ENODEV;
}
if ((flag & CMD_FLAG_REPEAT) == 0) {
/*
* Address is specified since argc > 3
*/
addr = simple_strtoul(argv[1], NULL, 16);
/*
* If another parameter, it is the length to display.
* Length is the number of objects, not number of bytes.
*/
if (argc > 2)
length = simple_strtoul(argv[2], NULL, 16);
}
nbytes = length * sizeof(u32);
do {
ulong linebytes = (nbytes > DISP_LINE_LEN) ?
DISP_LINE_LEN : nbytes;
for (k = 0; k < linebytes / sizeof(u32); ++k)
axi_read(axi_cur_bus, addr + k * sizeof(u32),
&linebuf[k]);
print_buffer(addr, (void *)linebuf, sizeof(u32),
linebytes / sizeof(u32),
DISP_LINE_LEN / sizeof(u32));
nbytes -= linebytes;
addr += linebytes;
if (ctrlc()) {
rc = 1;
break;
}
} while (nbytes > 0);
dp_last_addr = addr;
dp_last_length = length;
return rc;
+}
+static int do_axi_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
u32 writeval;
ulong addr, count;
if ((argc < 3) || (argc > 4))
return CMD_RET_USAGE;
/* Address is specified since argc > 3 */
addr = simple_strtoul(argv[1], NULL, 16);
/* Get the value to write. */
writeval = simple_strtoul(argv[2], NULL, 16);
/* Count ? */
if (argc == 4)
count = simple_strtoul(argv[3], NULL, 16);
else
count = 1;
while (count-- > 0)
axi_write(axi_cur_bus, addr + count * sizeof(u32), writeval);
Error check
Will add in v2.
return 0;
+}
+static cmd_tbl_t cmd_axi_sub[] = {
U_BOOT_CMD_MKENT(bus, 1, 1, do_axi_show_bus, "", ""),
U_BOOT_CMD_MKENT(dev, 1, 1, do_axi_bus_num, "", ""),
U_BOOT_CMD_MKENT(md, 3, 1, do_axi_md, "", ""),
U_BOOT_CMD_MKENT(mw, 4, 1, do_axi_mw, "", ""),
+};
+static int do_ihs_axi(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
cmd_tbl_t *c;
if (argc < 2)
return CMD_RET_USAGE;
/* Strip off leading 'axi' command argument */
argc--;
argv++;
c = find_cmd_tbl(argv[0], &cmd_axi_sub[0], ARRAY_SIZE(cmd_axi_sub));
if (c)
return c->cmd(cmdtp, flag, argc, argv);
else
return CMD_RET_USAGE;
+}
+static char axi_help_text[] =
"bus - show AXI bus info\n"
"axi dev [dev] - show or set current AXI bus\n"
"axi md address [# of objects] - read from AXI device\n"
"axi mw address value [count] - write to AXI device (fill)\n";
+U_BOOT_CMD(
axi, 7, 1, do_ihs_axi,
"AXI sub-system",
axi_help_text
+);
2.11.0
Regards, Simon
Best regards,
Mario