Message ID | 20170714125537.14895-42-mario.six@gdsys.cc |
---|---|
State | Rejected, archived |
Delegated to: | Mario Six |
Headers | show |
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 > + > 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() ? > + 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. > + 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 > + > + 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
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
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. + 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); + 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); + 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); + + 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 +);
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