150dcf89dSDirk Eibach /*
250dcf89dSDirk Eibach * (C) Copyright 2014
350dcf89dSDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
450dcf89dSDirk Eibach *
550dcf89dSDirk Eibach * SPDX-License-Identifier: GPL-2.0+
650dcf89dSDirk Eibach */
750dcf89dSDirk Eibach
850dcf89dSDirk Eibach #include <common.h>
950dcf89dSDirk Eibach #include <command.h>
10*24b852a7SSimon Glass #include <console.h>
1150dcf89dSDirk Eibach
1250dcf89dSDirk Eibach #include <gdsys_fpga.h>
1350dcf89dSDirk Eibach
1450dcf89dSDirk Eibach enum {
1550dcf89dSDirk Eibach STATE_TX_PACKET_BUILDING = 1<<0,
1650dcf89dSDirk Eibach STATE_TX_TRANSMITTING = 1<<1,
1750dcf89dSDirk Eibach STATE_TX_BUFFER_FULL = 1<<2,
1850dcf89dSDirk Eibach STATE_TX_ERR = 1<<3,
1950dcf89dSDirk Eibach STATE_RECEIVE_TIMEOUT = 1<<4,
2050dcf89dSDirk Eibach STATE_PROC_RX_STORE_TIMEOUT = 1<<5,
2150dcf89dSDirk Eibach STATE_PROC_RX_RECEIVE_TIMEOUT = 1<<6,
2250dcf89dSDirk Eibach STATE_RX_DIST_ERR = 1<<7,
2350dcf89dSDirk Eibach STATE_RX_LENGTH_ERR = 1<<8,
2450dcf89dSDirk Eibach STATE_RX_FRAME_CTR_ERR = 1<<9,
2550dcf89dSDirk Eibach STATE_RX_FCS_ERR = 1<<10,
2650dcf89dSDirk Eibach STATE_RX_PACKET_DROPPED = 1<<11,
2750dcf89dSDirk Eibach STATE_RX_DATA_LAST = 1<<12,
2850dcf89dSDirk Eibach STATE_RX_DATA_FIRST = 1<<13,
2950dcf89dSDirk Eibach STATE_RX_DATA_AVAILABLE = 1<<15,
3050dcf89dSDirk Eibach };
3150dcf89dSDirk Eibach
3250dcf89dSDirk Eibach enum {
3350dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE = 1<<12,
3450dcf89dSDirk Eibach CTRL_FLUSH_TRANSMIT_BUFFER = 1<<15,
3550dcf89dSDirk Eibach };
3650dcf89dSDirk Eibach
3750dcf89dSDirk Eibach enum {
3850dcf89dSDirk Eibach IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = 1<<5,
3950dcf89dSDirk Eibach IRQ_CPU_PACKET_TRANSMITTED_EVENT = 1<<6,
4050dcf89dSDirk Eibach IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = 1<<7,
4150dcf89dSDirk Eibach IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = 1<<8,
4250dcf89dSDirk Eibach };
4350dcf89dSDirk Eibach
4450dcf89dSDirk Eibach struct io_generic_packet {
4550dcf89dSDirk Eibach u16 target_address;
4650dcf89dSDirk Eibach u16 source_address;
4750dcf89dSDirk Eibach u8 packet_type;
4850dcf89dSDirk Eibach u8 bc;
4950dcf89dSDirk Eibach u16 packet_length;
5050dcf89dSDirk Eibach } __attribute__((__packed__));
5150dcf89dSDirk Eibach
5250dcf89dSDirk Eibach unsigned long long rx_ctr;
5350dcf89dSDirk Eibach unsigned long long tx_ctr;
5450dcf89dSDirk Eibach unsigned long long err_ctr;
5550dcf89dSDirk Eibach
io_check_status(unsigned int fpga,u16 status,bool silent)5650dcf89dSDirk Eibach static void io_check_status(unsigned int fpga, u16 status, bool silent)
5750dcf89dSDirk Eibach {
5850dcf89dSDirk Eibach u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR |
5950dcf89dSDirk Eibach STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR |
6050dcf89dSDirk Eibach STATE_RX_PACKET_DROPPED | STATE_TX_ERR;
6150dcf89dSDirk Eibach
6250dcf89dSDirk Eibach if (!(status & mask)) {
6350dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_status, status);
6450dcf89dSDirk Eibach return;
6550dcf89dSDirk Eibach }
6650dcf89dSDirk Eibach
6750dcf89dSDirk Eibach err_ctr++;
6850dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_status, status);
6950dcf89dSDirk Eibach
7050dcf89dSDirk Eibach if (silent)
7150dcf89dSDirk Eibach return;
7250dcf89dSDirk Eibach
7350dcf89dSDirk Eibach if (status & STATE_RX_PACKET_DROPPED)
7450dcf89dSDirk Eibach printf("RX_PACKET_DROPPED, status %04x\n", status);
7550dcf89dSDirk Eibach
7650dcf89dSDirk Eibach if (status & STATE_RX_DIST_ERR)
7750dcf89dSDirk Eibach printf("RX_DIST_ERR\n");
7850dcf89dSDirk Eibach if (status & STATE_RX_LENGTH_ERR)
7950dcf89dSDirk Eibach printf("RX_LENGTH_ERR\n");
8050dcf89dSDirk Eibach if (status & STATE_RX_FRAME_CTR_ERR)
8150dcf89dSDirk Eibach printf("RX_FRAME_CTR_ERR\n");
8250dcf89dSDirk Eibach if (status & STATE_RX_FCS_ERR)
8350dcf89dSDirk Eibach printf("RX_FCS_ERR\n");
8450dcf89dSDirk Eibach
8550dcf89dSDirk Eibach if (status & STATE_TX_ERR)
8650dcf89dSDirk Eibach printf("TX_ERR\n");
8750dcf89dSDirk Eibach }
8850dcf89dSDirk Eibach
io_send(unsigned int fpga,unsigned int size)8950dcf89dSDirk Eibach static void io_send(unsigned int fpga, unsigned int size)
9050dcf89dSDirk Eibach {
9150dcf89dSDirk Eibach unsigned int k;
9250dcf89dSDirk Eibach struct io_generic_packet packet = {
9350dcf89dSDirk Eibach .source_address = 1,
9450dcf89dSDirk Eibach .packet_type = 1,
9550dcf89dSDirk Eibach .packet_length = size,
9650dcf89dSDirk Eibach };
9750dcf89dSDirk Eibach u16 *p = (u16 *)&packet;
9850dcf89dSDirk Eibach
9950dcf89dSDirk Eibach for (k = 0; k < sizeof(packet) / 2; ++k)
10050dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, *p++);
10150dcf89dSDirk Eibach
10250dcf89dSDirk Eibach for (k = 0; k < (size + 1) / 2; ++k)
10350dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, k);
10450dcf89dSDirk Eibach
10550dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control,
10650dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
10750dcf89dSDirk Eibach
10850dcf89dSDirk Eibach tx_ctr++;
10950dcf89dSDirk Eibach }
11050dcf89dSDirk Eibach
io_receive(unsigned int fpga)11150dcf89dSDirk Eibach static void io_receive(unsigned int fpga)
11250dcf89dSDirk Eibach {
11350dcf89dSDirk Eibach unsigned int k = 0;
11450dcf89dSDirk Eibach u16 rx_tx_status;
11550dcf89dSDirk Eibach
11650dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
11750dcf89dSDirk Eibach
11850dcf89dSDirk Eibach while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
11950dcf89dSDirk Eibach u16 rx;
12050dcf89dSDirk Eibach
12150dcf89dSDirk Eibach if (rx_tx_status & STATE_RX_DATA_LAST)
12250dcf89dSDirk Eibach rx_ctr++;
12350dcf89dSDirk Eibach
12450dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.receive_data, &rx);
12550dcf89dSDirk Eibach
12650dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
12750dcf89dSDirk Eibach
12850dcf89dSDirk Eibach ++k;
12950dcf89dSDirk Eibach }
13050dcf89dSDirk Eibach }
13150dcf89dSDirk Eibach
io_reflect(unsigned int fpga)13250dcf89dSDirk Eibach static void io_reflect(unsigned int fpga)
13350dcf89dSDirk Eibach {
13450dcf89dSDirk Eibach u16 buffer[128];
13550dcf89dSDirk Eibach
13650dcf89dSDirk Eibach unsigned int k = 0;
13750dcf89dSDirk Eibach unsigned int n;
13850dcf89dSDirk Eibach u16 rx_tx_status;
13950dcf89dSDirk Eibach
14050dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
14150dcf89dSDirk Eibach
14250dcf89dSDirk Eibach while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
14350dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]);
14450dcf89dSDirk Eibach if (rx_tx_status & STATE_RX_DATA_LAST)
14550dcf89dSDirk Eibach break;
14650dcf89dSDirk Eibach
14750dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
14850dcf89dSDirk Eibach }
14950dcf89dSDirk Eibach
15050dcf89dSDirk Eibach if (!k)
15150dcf89dSDirk Eibach return;
15250dcf89dSDirk Eibach
15350dcf89dSDirk Eibach for (n = 0; n < k; ++n)
15450dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]);
15550dcf89dSDirk Eibach
15650dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control,
15750dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
15850dcf89dSDirk Eibach
15950dcf89dSDirk Eibach tx_ctr++;
16050dcf89dSDirk Eibach }
16150dcf89dSDirk Eibach
16250dcf89dSDirk Eibach /*
16350dcf89dSDirk Eibach * FPGA io-endpoint reflector
16450dcf89dSDirk Eibach *
16550dcf89dSDirk Eibach * Syntax:
16650dcf89dSDirk Eibach * ioreflect {fpga} {reportrate}
16750dcf89dSDirk Eibach */
do_ioreflect(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])16850dcf89dSDirk Eibach int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
16950dcf89dSDirk Eibach {
17050dcf89dSDirk Eibach unsigned int fpga;
17150dcf89dSDirk Eibach unsigned int rate = 0;
17250dcf89dSDirk Eibach unsigned long long last_seen = 0;
17350dcf89dSDirk Eibach
17450dcf89dSDirk Eibach if (argc < 2)
17550dcf89dSDirk Eibach return CMD_RET_USAGE;
17650dcf89dSDirk Eibach
17750dcf89dSDirk Eibach fpga = simple_strtoul(argv[1], NULL, 10);
17850dcf89dSDirk Eibach
17950dcf89dSDirk Eibach /*
18050dcf89dSDirk Eibach * If another parameter, it is the report rate in packets.
18150dcf89dSDirk Eibach */
18250dcf89dSDirk Eibach if (argc > 2)
18350dcf89dSDirk Eibach rate = simple_strtoul(argv[2], NULL, 10);
18450dcf89dSDirk Eibach
18550dcf89dSDirk Eibach /* enable receive path */
18650dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
18750dcf89dSDirk Eibach
18850dcf89dSDirk Eibach /* set device address to dummy 1*/
18950dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.device_address, 1);
19050dcf89dSDirk Eibach
19150dcf89dSDirk Eibach rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
19250dcf89dSDirk Eibach
19350dcf89dSDirk Eibach while (1) {
19450dcf89dSDirk Eibach u16 top_int;
19550dcf89dSDirk Eibach u16 rx_tx_status;
19650dcf89dSDirk Eibach
19750dcf89dSDirk Eibach FPGA_GET_REG(fpga, top_interrupt, &top_int);
19850dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
19950dcf89dSDirk Eibach
20050dcf89dSDirk Eibach io_check_status(fpga, rx_tx_status, true);
20150dcf89dSDirk Eibach if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) &&
20250dcf89dSDirk Eibach (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS))
20350dcf89dSDirk Eibach io_reflect(fpga);
20450dcf89dSDirk Eibach
20550dcf89dSDirk Eibach if (rate) {
20650dcf89dSDirk Eibach if (!(tx_ctr % rate) && (tx_ctr != last_seen))
20750dcf89dSDirk Eibach printf("refl %llu, err %llu\n", tx_ctr,
20850dcf89dSDirk Eibach err_ctr);
20950dcf89dSDirk Eibach last_seen = tx_ctr;
21050dcf89dSDirk Eibach }
21150dcf89dSDirk Eibach
21250dcf89dSDirk Eibach if (ctrlc())
21350dcf89dSDirk Eibach break;
21450dcf89dSDirk Eibach }
21550dcf89dSDirk Eibach
21650dcf89dSDirk Eibach return 0;
21750dcf89dSDirk Eibach }
21850dcf89dSDirk Eibach
21950dcf89dSDirk Eibach /*
22050dcf89dSDirk Eibach * FPGA io-endpoint looptest
22150dcf89dSDirk Eibach *
22250dcf89dSDirk Eibach * Syntax:
22350dcf89dSDirk Eibach * ioloop {fpga} {size} {rate}
22450dcf89dSDirk Eibach */
22550dcf89dSDirk Eibach #define DISP_LINE_LEN 16
do_ioloop(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])22650dcf89dSDirk Eibach int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
22750dcf89dSDirk Eibach {
22850dcf89dSDirk Eibach unsigned int fpga;
22950dcf89dSDirk Eibach unsigned int size;
23050dcf89dSDirk Eibach unsigned int rate = 0;
23150dcf89dSDirk Eibach
23250dcf89dSDirk Eibach if (argc < 3)
23350dcf89dSDirk Eibach return CMD_RET_USAGE;
23450dcf89dSDirk Eibach
23550dcf89dSDirk Eibach /*
23650dcf89dSDirk Eibach * FPGA is specified since argc > 2
23750dcf89dSDirk Eibach */
23850dcf89dSDirk Eibach fpga = simple_strtoul(argv[1], NULL, 10);
23950dcf89dSDirk Eibach
24050dcf89dSDirk Eibach /*
24150dcf89dSDirk Eibach * packet size is specified since argc > 2
24250dcf89dSDirk Eibach */
24350dcf89dSDirk Eibach size = simple_strtoul(argv[2], NULL, 10);
24450dcf89dSDirk Eibach
24550dcf89dSDirk Eibach /*
24650dcf89dSDirk Eibach * If another parameter, it is the test rate in packets per second.
24750dcf89dSDirk Eibach */
24850dcf89dSDirk Eibach if (argc > 3)
24950dcf89dSDirk Eibach rate = simple_strtoul(argv[3], NULL, 10);
25050dcf89dSDirk Eibach
25150dcf89dSDirk Eibach /* enable receive path */
25250dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
25350dcf89dSDirk Eibach
25450dcf89dSDirk Eibach /* set device address to dummy 1*/
25550dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.device_address, 1);
25650dcf89dSDirk Eibach
25750dcf89dSDirk Eibach rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
25850dcf89dSDirk Eibach
25950dcf89dSDirk Eibach while (1) {
26050dcf89dSDirk Eibach u16 top_int;
26150dcf89dSDirk Eibach u16 rx_tx_status;
26250dcf89dSDirk Eibach
26350dcf89dSDirk Eibach FPGA_GET_REG(fpga, top_interrupt, &top_int);
26450dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
26550dcf89dSDirk Eibach
26650dcf89dSDirk Eibach io_check_status(fpga, rx_tx_status, false);
26750dcf89dSDirk Eibach if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)
26850dcf89dSDirk Eibach io_send(fpga, size);
26950dcf89dSDirk Eibach if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS)
27050dcf89dSDirk Eibach io_receive(fpga);
27150dcf89dSDirk Eibach
27250dcf89dSDirk Eibach if (rate) {
27350dcf89dSDirk Eibach if (ctrlc())
27450dcf89dSDirk Eibach break;
27550dcf89dSDirk Eibach udelay(1000000 / rate);
27650dcf89dSDirk Eibach if (!(tx_ctr % rate))
27750dcf89dSDirk Eibach printf("d %lld, tx %llu, rx %llu, err %llu\n",
27850dcf89dSDirk Eibach tx_ctr - rx_ctr, tx_ctr, rx_ctr,
27950dcf89dSDirk Eibach err_ctr);
28050dcf89dSDirk Eibach }
28150dcf89dSDirk Eibach }
28250dcf89dSDirk Eibach
28350dcf89dSDirk Eibach return 0;
28450dcf89dSDirk Eibach }
28550dcf89dSDirk Eibach
28650dcf89dSDirk Eibach U_BOOT_CMD(
28750dcf89dSDirk Eibach ioloop, 4, 0, do_ioloop,
28850dcf89dSDirk Eibach "fpga io-endpoint looptest",
28950dcf89dSDirk Eibach "fpga packetsize [packets/sec]"
29050dcf89dSDirk Eibach );
29150dcf89dSDirk Eibach
29250dcf89dSDirk Eibach U_BOOT_CMD(
29350dcf89dSDirk Eibach ioreflect, 3, 0, do_ioreflect,
29450dcf89dSDirk Eibach "fpga io-endpoint reflector",
29550dcf89dSDirk Eibach "fpga reportrate"
29650dcf89dSDirk Eibach );
297