diff options
Diffstat (limited to 'roms/u-boot/board/gdsys/common/cmd_ioloop.c')
-rw-r--r-- | roms/u-boot/board/gdsys/common/cmd_ioloop.c | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/roms/u-boot/board/gdsys/common/cmd_ioloop.c b/roms/u-boot/board/gdsys/common/cmd_ioloop.c new file mode 100644 index 000000000..658756d98 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/cmd_ioloop.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <linux/bitops.h> +#include <linux/delay.h> + +#include <gdsys_fpga.h> + +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +#include <dm.h> +#include <misc.h> +#include <regmap.h> +#include <sysinfo.h> + +#include "../../../drivers/misc/gdsys_soc.h" +#include "../../../drivers/misc/gdsys_ioep.h" +#include "../../../drivers/misc/ihs_fpga.h" + +const int HEADER_WORDS = sizeof(struct io_generic_packet) / 2; +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +enum status_print_type { + STATUS_LOUD = 0, + STATUS_SILENT = 1, +}; + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +enum { + STATE_TX_PACKET_BUILDING = BIT(0), + STATE_TX_TRANSMITTING = BIT(1), + STATE_TX_BUFFER_FULL = BIT(2), + STATE_TX_ERR = BIT(3), + STATE_RECEIVE_TIMEOUT = BIT(4), + STATE_PROC_RX_STORE_TIMEOUT = BIT(5), + STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6), + STATE_RX_DIST_ERR = BIT(7), + STATE_RX_LENGTH_ERR = BIT(8), + STATE_RX_FRAME_CTR_ERR = BIT(9), + STATE_RX_FCS_ERR = BIT(10), + STATE_RX_PACKET_DROPPED = BIT(11), + STATE_RX_DATA_LAST = BIT(12), + STATE_RX_DATA_FIRST = BIT(13), + STATE_RX_DATA_AVAILABLE = BIT(15), +}; + +enum { + IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5), + IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6), + IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7), + IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8), +}; + +enum { + CTRL_PROC_RECEIVE_ENABLE = BIT(12), + CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15), +}; + +struct io_generic_packet { + u16 target_address; + u16 source_address; + u8 packet_type; + u8 bc; + u16 packet_length; +} __attribute__((__packed__)); +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +unsigned long long rx_ctr; +unsigned long long tx_ctr; +unsigned long long err_ctr; +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +struct udevice *dev; +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_check_status(uint fpga, u16 status, enum status_print_type type) +{ + u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR | + STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR | + STATE_RX_PACKET_DROPPED | STATE_TX_ERR; + + if (!(status & mask)) { + FPGA_SET_REG(fpga, ep.rx_tx_status, status); + return; + } + + err_ctr++; + FPGA_SET_REG(fpga, ep.rx_tx_status, status); + + if (type == STATUS_SILENT) + return; + + if (status & STATE_RX_PACKET_DROPPED) + printf("RX_PACKET_DROPPED, status %04x\n", status); + + if (status & STATE_RX_DIST_ERR) + printf("RX_DIST_ERR\n"); + if (status & STATE_RX_LENGTH_ERR) + printf("RX_LENGTH_ERR\n"); + if (status & STATE_RX_FRAME_CTR_ERR) + printf("RX_FRAME_CTR_ERR\n"); + if (status & STATE_RX_FCS_ERR) + printf("RX_FCS_ERR\n"); + + if (status & STATE_TX_ERR) + printf("TX_ERR\n"); +} +#else +static void io_check_status(struct udevice *dev, enum status_print_type type) +{ + u16 status = 0; + int ret; + + ret = misc_call(dev, 0, NULL, 0, &status, 0); + if (!ret) + return; + + err_ctr++; + + if (type != STATUS_LOUD) + return; + + if (status & STATE_RX_PACKET_DROPPED) + printf("RX_PACKET_DROPPED, status %04x\n", status); + + if (status & STATE_RX_DIST_ERR) + printf("RX_DIST_ERR\n"); + if (status & STATE_RX_LENGTH_ERR) + printf("RX_LENGTH_ERR\n"); + if (status & STATE_RX_FRAME_CTR_ERR) + printf("RX_FRAME_CTR_ERR\n"); + if (status & STATE_RX_FCS_ERR) + printf("RX_FCS_ERR\n"); + + if (status & STATE_TX_ERR) + printf("TX_ERR\n"); +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_send(uint fpga, uint size) +{ + uint k; + struct io_generic_packet packet = { + .source_address = 1, + .packet_type = 1, + .packet_length = size, + }; + u16 *p = (u16 *)&packet; + + for (k = 0; k < sizeof(packet) / 2; ++k) + FPGA_SET_REG(fpga, ep.transmit_data, *p++); + + for (k = 0; k < (size + 1) / 2; ++k) + FPGA_SET_REG(fpga, ep.transmit_data, k); + + FPGA_SET_REG(fpga, ep.rx_tx_control, + CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); + + tx_ctr++; +} +#else +static void io_send(struct udevice *dev, uint size) +{ + uint k; + u16 buffer[HEADER_WORDS + 128]; + struct io_generic_packet header = { + .source_address = 1, + .packet_type = 1, + .packet_length = size, + }; + const uint words = (size + 1) / 2; + + memcpy(buffer, &header, 2 * HEADER_WORDS); + for (k = 0; k < words; ++k) + buffer[k + HEADER_WORDS] = (2 * k + 1) + ((2 * k) << 8); + + misc_write(dev, 0, buffer, HEADER_WORDS + words); + + tx_ctr++; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_receive(uint fpga) +{ + u16 rx_tx_status; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { + u16 rx; + + if (rx_tx_status & STATE_RX_DATA_LAST) + rx_ctr++; + + FPGA_GET_REG(fpga, ep.receive_data, &rx); + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + } +} +#else +static void io_receive(struct udevice *dev) +{ + u16 buffer[HEADER_WORDS + 128]; + + if (!misc_read(dev, 0, buffer, 0)) + rx_ctr++; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_reflect(uint fpga) +{ + u16 buffer[128]; + + uint k = 0; + uint n; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { + FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]); + if (rx_tx_status & STATE_RX_DATA_LAST) + break; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + } + + if (!k) + return; + + for (n = 0; n < k; ++n) + FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]); + + FPGA_SET_REG(fpga, ep.rx_tx_control, + CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); + + tx_ctr++; +} +#else +static void io_reflect(struct udevice *dev) +{ + u16 buffer[HEADER_WORDS + 128]; + struct io_generic_packet *header; + + if (misc_read(dev, 0, buffer, 0)) + return; + + header = (struct io_generic_packet *)&buffer; + + misc_write(dev, 0, buffer, HEADER_WORDS + header->packet_length); +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +/* + * FPGA io-endpoint reflector + * + * Syntax: + * ioreflect {fpga} {reportrate} + */ +int do_ioreflect(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint fpga; + uint rate = 0; + unsigned long long last_seen = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + fpga = simple_strtoul(argv[1], NULL, 10); + + /* + * If another parameter, it is the report rate in packets. + */ + if (argc > 2) + rate = simple_strtoul(argv[2], NULL, 10); + + /* Enable receive path */ + FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); + + /* Set device address to dummy 1*/ + FPGA_SET_REG(fpga, ep.device_address, 1); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + u16 top_int; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, top_interrupt, &top_int); + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + io_check_status(fpga, rx_tx_status, STATUS_SILENT); + if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) && + (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)) + io_reflect(fpga); + + if (rate) { + if (!(tx_ctr % rate) && (tx_ctr != last_seen)) + printf("refl %llu, err %llu\n", tx_ctr, + err_ctr); + last_seen = tx_ctr; + } + + if (ctrlc()) + break; + } + + return 0; +} +#else +/* + * FPGA io-endpoint reflector + * + * Syntax: + * ioreflect {reportrate} + */ +int do_ioreflect(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *fpga; + struct regmap *map; + uint rate = 0; + unsigned long long last_seen = 0; + + if (!dev) { + printf("No device selected\n"); + return 1; + } + + gdsys_soc_get_fpga(dev, &fpga); + regmap_init_mem(dev_ofnode(dev), &map); + + /* Enable receive path */ + misc_set_enabled(dev, true); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + uint top_int; + + ihs_fpga_get(map, top_interrupt, &top_int); + io_check_status(dev, STATUS_SILENT); + if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) && + (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)) + io_reflect(dev); + + if (rate) { + if (!(tx_ctr % rate) && (tx_ctr != last_seen)) + printf("refl %llu, err %llu\n", tx_ctr, + err_ctr); + last_seen = tx_ctr; + } + + if (ctrlc()) + break; + } + + return 0; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#define DISP_LINE_LEN 16 + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +/* + * FPGA io-endpoint looptest + * + * Syntax: + * ioloop {fpga} {size} {rate} + */ +int do_ioloop(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint fpga; + uint size; + uint rate = 0; + + if (argc < 3) + return CMD_RET_USAGE; + + /* + * FPGA is specified since argc > 2 + */ + fpga = simple_strtoul(argv[1], NULL, 10); + + /* + * packet size is specified since argc > 2 + */ + size = simple_strtoul(argv[2], NULL, 10); + + /* + * If another parameter, it is the test rate in packets per second. + */ + if (argc > 3) + rate = simple_strtoul(argv[3], NULL, 10); + + /* enable receive path */ + FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); + + /* set device address to dummy 1*/ + FPGA_SET_REG(fpga, ep.device_address, 1); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + u16 top_int; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, top_interrupt, &top_int); + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + io_check_status(fpga, rx_tx_status, STATUS_LOUD); + if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS) + io_send(fpga, size); + if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) + io_receive(fpga); + + if (rate) { + if (ctrlc()) + break; + udelay(1000000 / rate); + if (!(tx_ctr % rate)) + printf("d %llu, tx %llu, rx %llu, err %llu\n", + tx_ctr - rx_ctr, tx_ctr, rx_ctr, + err_ctr); + } + } + + return 0; +} +#else +/* + * FPGA io-endpoint looptest + * + * Syntax: + * ioloop {size} {rate} + */ +int do_ioloop(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint size; + uint rate = 0; + struct udevice *fpga; + struct regmap *map; + + if (!dev) { + printf("No device selected\n"); + return 1; + } + + gdsys_soc_get_fpga(dev, &fpga); + regmap_init_mem(dev_ofnode(dev), &map); + + if (argc < 2) + return CMD_RET_USAGE; + + /* + * packet size is specified since argc > 1 + */ + size = simple_strtoul(argv[2], NULL, 10); + + /* + * If another parameter, it is the test rate in packets per second. + */ + if (argc > 2) + rate = simple_strtoul(argv[3], NULL, 10); + + /* Enable receive path */ + misc_set_enabled(dev, true); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + uint top_int; + + if (ctrlc()) + break; + + ihs_fpga_get(map, top_interrupt, &top_int); + + io_check_status(dev, STATUS_LOUD); + if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS) + io_send(dev, size); + if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) + io_receive(dev); + + if (rate) { + udelay(1000000 / rate); + if (!(tx_ctr % rate)) + printf("d %llu, tx %llu, rx %llu, err %llu\n", + tx_ctr - rx_ctr, tx_ctr, rx_ctr, + err_ctr); + } + } + return 0; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +int do_iodev(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *ioep = NULL; + struct udevice *sysinfo; + char name[8]; + int ret; + + if (sysinfo_get(&sysinfo)) + return CMD_RET_FAILURE; + + if (argc > 1) { + int i = simple_strtoul(argv[1], NULL, 10); + + snprintf(name, sizeof(name), "ioep%d", i); + + ret = uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, name, + &ioep); + + if (ret || !ioep) { + printf("Invalid IOEP %d\n", i); + return CMD_RET_FAILURE; + } + + dev = ioep; + } else { + int i = 0; + + while (1) { + snprintf(name, sizeof(name), "ioep%d", i); + + ret = uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, + name, &ioep); + + if (ret || !ioep) + break; + + printf("IOEP %d:\t%s\n", i++, ioep->name); + } + + if (dev) + printf("\nSelected IOEP: %s\n", dev->name); + else + puts("\nNo IOEP selected.\n"); + } + + return 0; +} +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +U_BOOT_CMD( + ioloop, 4, 0, do_ioloop, + "fpga io-endpoint looptest", + "fpga packetsize [packets/sec]" +); + +U_BOOT_CMD( + ioreflect, 3, 0, do_ioreflect, + "fpga io-endpoint reflector", + "fpga reportrate" +); +#else +U_BOOT_CMD( + ioloop, 3, 0, do_ioloop, + "fpga io-endpoint looptest", + "packetsize [packets/sec]" +); + +U_BOOT_CMD( + ioreflect, 2, 0, do_ioreflect, + "fpga io-endpoint reflector", + "reportrate" +); + +U_BOOT_CMD( + iodev, 2, 0, do_iodev, + "fpga io-endpoint listing/selection", + "[ioep device to select]" +); +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ |