Add a command to debug the IHS FPGA's bus. Signed-off-by: Mario Six <mario....@gdsys.cc> --- cmd/Kconfig | 5 + cmd/Makefile | 2 + cmd/fpgamap.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 cmd/fpgamap.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 136836d146..b669b9d6ac 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -976,6 +976,11 @@ config CMD_USB_MASS_STORAGE help USB mass storage support +config CMD_FPGAMAP + bool "fpgamap" + help + Enable the command "fpgamap" to access register maps of FPGAs. + endmenu diff --git a/cmd/Makefile b/cmd/Makefile index 9a358e4801..6fcb89e118 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_FPGAMAP) += fpgamap.o + # Power obj-$(CONFIG_CMD_PMIC) += pmic.o obj-$(CONFIG_CMD_REGULATOR) += regulator.o diff --git a/cmd/fpgamap.c b/cmd/fpgamap.c new file mode 100644 index 0000000000..56af558361 --- /dev/null +++ b/cmd/fpgamap.c @@ -0,0 +1,306 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc + * + * based on the fpgad command, which is + * + * (C) Copyright 2013 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eib...@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <command.h> +#include <console.h> +#include <fpgamap.h> + +static struct udevice *fpgamap_cur; +static uint dp_last_size; +static uint dp_last_addr; +static uint dp_last_length = 0x40; + +static void show_fpgamap(struct udevice *fpgamap) +{ + struct udevice *dev; + + printf("Bus %d:\t%s", fpgamap->req_seq, fpgamap->name); + if (device_active(fpgamap)) + printf(" (active %d)", fpgamap->seq); + printf("\n"); + for (device_find_first_child(fpgamap, &dev); + dev; + device_find_next_child(&dev)) + printf(" %s\n", dev->name); +} + +static int do_fpgamap_show_fpgamap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + if (argc == 1) { + /* show all FPGAs */ + struct udevice *fpgamap; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_FPGAMAP, &uc); + if (ret) + return CMD_RET_FAILURE; + uclass_foreach_dev(fpgamap, uc) + show_fpgamap(fpgamap); + } else { + int i; + + /* show specific fpgamap */ + i = simple_strtoul(argv[1], NULL, 10); + + struct udevice *fpgamap; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_FPGAMAP, i, &fpgamap); + if (ret) { + printf("Invalid fpgamap %d: err=%d\n", i, ret); + return CMD_RET_FAILURE; + } + show_fpgamap(fpgamap); + } + + return 0; +} + +static int cmd_fpgamap_set_fpgamap_num(unsigned int fpgamapnum) +{ + struct udevice *fpgamap; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_FPGAMAP, fpgamapnum, &fpgamap); + if (ret) { + debug("%s: No fpgamap %d\n", __func__, fpgamapnum); + return ret; + } + fpgamap_cur = fpgamap; + + return 0; +} + +static int fpgamap_get_cur_fpgamap(struct udevice **fpgamapp) +{ + if (!fpgamap_cur) { + puts("No fpgamap selected\n"); + return -ENODEV; + } + *fpgamapp = fpgamap_cur; + + return 0; +} + +static int do_fpgamap_fpgamap_num(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int ret = 0; + int fpgamap_no; + + if (argc == 1) { + /* querying current setting */ + struct udevice *fpgamap; + + if (!fpgamap_get_cur_fpgamap(&fpgamap)) + fpgamap_no = fpgamap->seq; + else + fpgamap_no = -1; + printf("Current fpgamap is %d\n", fpgamap_no); + } else { + fpgamap_no = simple_strtoul(argv[1], NULL, 10); + printf("Setting fpgamap to %d\n", fpgamap_no); + + ret = cmd_fpgamap_set_fpgamap_num(fpgamap_no); + + if (ret) + printf("Failure changing fpgamap number (%d)\n", ret); + } + + return ret ? CMD_RET_FAILURE : 0; +} + +#define DISP_LINE_LEN 16 + +int do_fpgamap_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int k; + ulong addr, size, length; + int rc = 0; + u16 linebuf[DISP_LINE_LEN / sizeof(u16)]; + ulong nbytes; + enum fpgamap_size_t size_param; + + /* + * We use the last specified parameters, unless new ones are + * entered. + */ + size = dp_last_size; + addr = dp_last_addr; + length = dp_last_length; + + if (argc < 3) + return CMD_RET_USAGE; + + if (!fpgamap_cur) { + puts("No fpgamap selected\n"); + return CMD_RET_FAILURE; + } + + if ((flag & CMD_FLAG_REPEAT) == 0) { + /* + * Size is specified since argc > 3 + */ + size = simple_strtoul(argv[1], NULL, 10); + + /* + * Address is specified since argc > 3 + */ + addr = simple_strtoul(argv[2], NULL, 16); + + /* + * If another parameter, it is the length to display. + * Length is the number of objects, not number of bytes. + */ + if (argc > 3) + length = simple_strtoul(argv[3], NULL, 16); + } + + switch (size) { + case 1: + size_param = FPGAMAP_SIZE_8; + break; + case 2: + size_param = FPGAMAP_SIZE_16; + break; + case 4: + size_param = FPGAMAP_SIZE_32; + break; + default: + printf("Unknown size: %lu\n", size); + return CMD_RET_FAILURE; + } + + nbytes = length * size; + do { + ulong linebytes = min(nbytes, (ulong)DISP_LINE_LEN); + + for (k = 0; k < linebytes / size; ++k) + rc = fpgamap_read(fpgamap_cur, addr + k * size, + &linebuf[k], size_param); + if (rc) + break; + + print_buffer(addr, (void *)linebuf, size, + linebytes / size, + DISP_LINE_LEN / size); + + nbytes -= linebytes; + addr += linebytes; + if (ctrlc()) { + rc = 1; + break; + } + } while (nbytes > 0); + + dp_last_size = size; + dp_last_addr = addr; + dp_last_length = length; + + return rc ? CMD_RET_FAILURE : 0; +} + +static int do_fpgamap_mw(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u16 writeval; + ulong size, addr, count; + enum fpgamap_size_t size_param; + + if (argc < 4 || argc > 5) + return CMD_RET_USAGE; + + if (!fpgamap_cur) { + puts("No fpgamap selected\n"); + return CMD_RET_FAILURE; + } + + /* Size is specified since argc > 4 */ + size = simple_strtoul(argv[1], NULL, 10); + + /* Address is specified since argc > 4 */ + addr = simple_strtoul(argv[2], NULL, 16); + + /* Get the value to write. */ + writeval = simple_strtoul(argv[3], NULL, 16); + + /* Count ? */ + if (argc == 4) + count = simple_strtoul(argv[4], NULL, 16); + else + count = 1; + + switch (size) { + case 1: + size_param = FPGAMAP_SIZE_8; + break; + case 2: + size_param = FPGAMAP_SIZE_16; + break; + case 4: + size_param = FPGAMAP_SIZE_32; + break; + default: + printf("Unknown size: %lu\n", size); + return CMD_RET_FAILURE; + } + + while (count-- > 0) + fpgamap_write(fpgamap_cur, addr + count * size, &writeval, + size_param); + + return 0; +} + +static cmd_tbl_t cmd_fpgamap_sub[] = { + U_BOOT_CMD_MKENT(show, 1, 1, do_fpgamap_show_fpgamap, "", ""), + U_BOOT_CMD_MKENT(dev, 1, 1, do_fpgamap_fpgamap_num, "", ""), + U_BOOT_CMD_MKENT(md, 3, 1, do_fpgamap_md, "", ""), + U_BOOT_CMD_MKENT(mw, 4, 1, do_fpgamap_mw, "", ""), +}; + +static int do_fpgamap(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 'fpgamap' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], &cmd_fpgamap_sub[0], + ARRAY_SIZE(cmd_fpgamap_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +static char fpgamap_help_text[] = + "show - show FPGA register map info\n" + "fpgamap dev [dev] - show or set current FPGA register map\n" + "fpgamap md size address [# of objects] - read from FPGA register map\n" + "fpgamap mw size address value [count] - write to FPGA register map (fill)\n"; + +U_BOOT_CMD( + fpgamap, 7, 1, do_fpgamap, + "FPGA sub-system", + fpgamap_help_text +); -- 2.16.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot