mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 12:33:41 +00:00
83d290c56f
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
295 lines
6.1 KiB
C
295 lines
6.1 KiB
C
// 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 <gdsys_fpga.h>
|
|
|
|
enum {
|
|
STATE_TX_PACKET_BUILDING = 1<<0,
|
|
STATE_TX_TRANSMITTING = 1<<1,
|
|
STATE_TX_BUFFER_FULL = 1<<2,
|
|
STATE_TX_ERR = 1<<3,
|
|
STATE_RECEIVE_TIMEOUT = 1<<4,
|
|
STATE_PROC_RX_STORE_TIMEOUT = 1<<5,
|
|
STATE_PROC_RX_RECEIVE_TIMEOUT = 1<<6,
|
|
STATE_RX_DIST_ERR = 1<<7,
|
|
STATE_RX_LENGTH_ERR = 1<<8,
|
|
STATE_RX_FRAME_CTR_ERR = 1<<9,
|
|
STATE_RX_FCS_ERR = 1<<10,
|
|
STATE_RX_PACKET_DROPPED = 1<<11,
|
|
STATE_RX_DATA_LAST = 1<<12,
|
|
STATE_RX_DATA_FIRST = 1<<13,
|
|
STATE_RX_DATA_AVAILABLE = 1<<15,
|
|
};
|
|
|
|
enum {
|
|
CTRL_PROC_RECEIVE_ENABLE = 1<<12,
|
|
CTRL_FLUSH_TRANSMIT_BUFFER = 1<<15,
|
|
};
|
|
|
|
enum {
|
|
IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = 1<<5,
|
|
IRQ_CPU_PACKET_TRANSMITTED_EVENT = 1<<6,
|
|
IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = 1<<7,
|
|
IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = 1<<8,
|
|
};
|
|
|
|
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;
|
|
|
|
static void io_check_status(unsigned int fpga, u16 status, bool silent)
|
|
{
|
|
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");
|
|
}
|
|
|
|
static void io_send(unsigned int fpga, unsigned int size)
|
|
{
|
|
unsigned int 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++;
|
|
}
|
|
|
|
static void io_receive(unsigned int fpga)
|
|
{
|
|
unsigned int k = 0;
|
|
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);
|
|
|
|
++k;
|
|
}
|
|
}
|
|
|
|
static void io_reflect(unsigned int fpga)
|
|
{
|
|
u16 buffer[128];
|
|
|
|
unsigned int k = 0;
|
|
unsigned int 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++;
|
|
}
|
|
|
|
/*
|
|
* FPGA io-endpoint reflector
|
|
*
|
|
* Syntax:
|
|
* ioreflect {fpga} {reportrate}
|
|
*/
|
|
int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int fpga;
|
|
unsigned int 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, 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;
|
|
}
|
|
|
|
/*
|
|
* FPGA io-endpoint looptest
|
|
*
|
|
* Syntax:
|
|
* ioloop {fpga} {size} {rate}
|
|
*/
|
|
#define DISP_LINE_LEN 16
|
|
int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int fpga;
|
|
unsigned int size;
|
|
unsigned int 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, 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))
|
|
printf("d %lld, tx %llu, rx %llu, err %llu\n",
|
|
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"
|
|
);
|