2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2014-11-13 18:21:18 +00:00
|
|
|
/*
|
|
|
|
* (C) Copyright 2014
|
|
|
|
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <command.h>
|
2015-11-09 06:47:45 +00:00
|
|
|
#include <console.h>
|
2014-11-13 18:21:18 +00:00
|
|
|
|
|
|
|
#include <gdsys_fpga.h>
|
|
|
|
|
|
|
|
enum {
|
2019-03-29 09:18:12 +00:00
|
|
|
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),
|
2014-11-13 18:21:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2019-03-29 09:18:12 +00:00
|
|
|
CTRL_PROC_RECEIVE_ENABLE = BIT(12),
|
|
|
|
CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15),
|
2014-11-13 18:21:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2019-03-29 09:18:12 +00:00
|
|
|
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),
|
2014-11-13 18:21:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct io_generic_packet {
|
|
|
|
u16 target_address;
|
|
|
|
u16 source_address;
|
|
|
|
u8 packet_type;
|
|
|
|
u8 bc;
|
|
|
|
u16 packet_length;
|
|
|
|
} __attribute__((__packed__));
|
|
|
|
|
|
|
|
unsigned long long rx_ctr;
|
|
|
|
unsigned long long tx_ctr;
|
|
|
|
unsigned long long err_ctr;
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
static void io_check_status(uint fpga, u16 status, bool silent)
|
2014-11-13 18:21:18 +00:00
|
|
|
{
|
|
|
|
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 (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");
|
|
|
|
}
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
static void io_send(uint fpga, uint size)
|
2014-11-13 18:21:18 +00:00
|
|
|
{
|
2019-03-29 09:18:12 +00:00
|
|
|
uint k;
|
2014-11-13 18:21:18 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
static void io_receive(uint fpga)
|
2014-11-13 18:21:18 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
static void io_reflect(uint fpga)
|
2014-11-13 18:21:18 +00:00
|
|
|
{
|
|
|
|
u16 buffer[128];
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
uint k = 0;
|
|
|
|
uint n;
|
2014-11-13 18:21:18 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FPGA io-endpoint reflector
|
|
|
|
*
|
|
|
|
* Syntax:
|
|
|
|
* ioreflect {fpga} {reportrate}
|
|
|
|
*/
|
|
|
|
int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
|
|
{
|
2019-03-29 09:18:12 +00:00
|
|
|
uint fpga;
|
|
|
|
uint rate = 0;
|
2014-11-13 18:21:18 +00:00
|
|
|
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);
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
/* Enable receive path */
|
2014-11-13 18:21:18 +00:00
|
|
|
FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
/* Set device address to dummy 1*/
|
2014-11-13 18:21:18 +00:00
|
|
|
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, true);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-03-29 09:18:12 +00:00
|
|
|
#define DISP_LINE_LEN 16
|
|
|
|
|
2014-11-13 18:21:18 +00:00
|
|
|
/*
|
|
|
|
* FPGA io-endpoint looptest
|
|
|
|
*
|
|
|
|
* Syntax:
|
|
|
|
* ioloop {fpga} {size} {rate}
|
|
|
|
*/
|
|
|
|
int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
|
|
{
|
2019-03-29 09:18:12 +00:00
|
|
|
uint fpga;
|
|
|
|
uint size;
|
|
|
|
uint rate = 0;
|
2014-11-13 18:21:18 +00:00
|
|
|
|
|
|
|
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, false);
|
|
|
|
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))
|
2019-03-29 09:18:12 +00:00
|
|
|
printf("d %llu, tx %llu, rx %llu, err %llu\n",
|
2014-11-13 18:21:18 +00:00
|
|
|
tx_ctr - rx_ctr, tx_ctr, rx_ctr,
|
|
|
|
err_ctr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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"
|
|
|
|
);
|