1*50dcf89dSDirk Eibach /* 2*50dcf89dSDirk Eibach * (C) Copyright 2014 3*50dcf89dSDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 4*50dcf89dSDirk Eibach * 5*50dcf89dSDirk Eibach * SPDX-License-Identifier: GPL-2.0+ 6*50dcf89dSDirk Eibach */ 7*50dcf89dSDirk Eibach 8*50dcf89dSDirk Eibach #include <common.h> 9*50dcf89dSDirk Eibach #include <command.h> 10*50dcf89dSDirk Eibach 11*50dcf89dSDirk Eibach #include <gdsys_fpga.h> 12*50dcf89dSDirk Eibach 13*50dcf89dSDirk Eibach enum { 14*50dcf89dSDirk Eibach STATE_TX_PACKET_BUILDING = 1<<0, 15*50dcf89dSDirk Eibach STATE_TX_TRANSMITTING = 1<<1, 16*50dcf89dSDirk Eibach STATE_TX_BUFFER_FULL = 1<<2, 17*50dcf89dSDirk Eibach STATE_TX_ERR = 1<<3, 18*50dcf89dSDirk Eibach STATE_RECEIVE_TIMEOUT = 1<<4, 19*50dcf89dSDirk Eibach STATE_PROC_RX_STORE_TIMEOUT = 1<<5, 20*50dcf89dSDirk Eibach STATE_PROC_RX_RECEIVE_TIMEOUT = 1<<6, 21*50dcf89dSDirk Eibach STATE_RX_DIST_ERR = 1<<7, 22*50dcf89dSDirk Eibach STATE_RX_LENGTH_ERR = 1<<8, 23*50dcf89dSDirk Eibach STATE_RX_FRAME_CTR_ERR = 1<<9, 24*50dcf89dSDirk Eibach STATE_RX_FCS_ERR = 1<<10, 25*50dcf89dSDirk Eibach STATE_RX_PACKET_DROPPED = 1<<11, 26*50dcf89dSDirk Eibach STATE_RX_DATA_LAST = 1<<12, 27*50dcf89dSDirk Eibach STATE_RX_DATA_FIRST = 1<<13, 28*50dcf89dSDirk Eibach STATE_RX_DATA_AVAILABLE = 1<<15, 29*50dcf89dSDirk Eibach }; 30*50dcf89dSDirk Eibach 31*50dcf89dSDirk Eibach enum { 32*50dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE = 1<<12, 33*50dcf89dSDirk Eibach CTRL_FLUSH_TRANSMIT_BUFFER = 1<<15, 34*50dcf89dSDirk Eibach }; 35*50dcf89dSDirk Eibach 36*50dcf89dSDirk Eibach enum { 37*50dcf89dSDirk Eibach IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = 1<<5, 38*50dcf89dSDirk Eibach IRQ_CPU_PACKET_TRANSMITTED_EVENT = 1<<6, 39*50dcf89dSDirk Eibach IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = 1<<7, 40*50dcf89dSDirk Eibach IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = 1<<8, 41*50dcf89dSDirk Eibach }; 42*50dcf89dSDirk Eibach 43*50dcf89dSDirk Eibach struct io_generic_packet { 44*50dcf89dSDirk Eibach u16 target_address; 45*50dcf89dSDirk Eibach u16 source_address; 46*50dcf89dSDirk Eibach u8 packet_type; 47*50dcf89dSDirk Eibach u8 bc; 48*50dcf89dSDirk Eibach u16 packet_length; 49*50dcf89dSDirk Eibach } __attribute__((__packed__)); 50*50dcf89dSDirk Eibach 51*50dcf89dSDirk Eibach unsigned long long rx_ctr; 52*50dcf89dSDirk Eibach unsigned long long tx_ctr; 53*50dcf89dSDirk Eibach unsigned long long err_ctr; 54*50dcf89dSDirk Eibach 55*50dcf89dSDirk Eibach static void io_check_status(unsigned int fpga, u16 status, bool silent) 56*50dcf89dSDirk Eibach { 57*50dcf89dSDirk Eibach u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR | 58*50dcf89dSDirk Eibach STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR | 59*50dcf89dSDirk Eibach STATE_RX_PACKET_DROPPED | STATE_TX_ERR; 60*50dcf89dSDirk Eibach 61*50dcf89dSDirk Eibach if (!(status & mask)) { 62*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_status, status); 63*50dcf89dSDirk Eibach return; 64*50dcf89dSDirk Eibach } 65*50dcf89dSDirk Eibach 66*50dcf89dSDirk Eibach err_ctr++; 67*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_status, status); 68*50dcf89dSDirk Eibach 69*50dcf89dSDirk Eibach if (silent) 70*50dcf89dSDirk Eibach return; 71*50dcf89dSDirk Eibach 72*50dcf89dSDirk Eibach if (status & STATE_RX_PACKET_DROPPED) 73*50dcf89dSDirk Eibach printf("RX_PACKET_DROPPED, status %04x\n", status); 74*50dcf89dSDirk Eibach 75*50dcf89dSDirk Eibach if (status & STATE_RX_DIST_ERR) 76*50dcf89dSDirk Eibach printf("RX_DIST_ERR\n"); 77*50dcf89dSDirk Eibach if (status & STATE_RX_LENGTH_ERR) 78*50dcf89dSDirk Eibach printf("RX_LENGTH_ERR\n"); 79*50dcf89dSDirk Eibach if (status & STATE_RX_FRAME_CTR_ERR) 80*50dcf89dSDirk Eibach printf("RX_FRAME_CTR_ERR\n"); 81*50dcf89dSDirk Eibach if (status & STATE_RX_FCS_ERR) 82*50dcf89dSDirk Eibach printf("RX_FCS_ERR\n"); 83*50dcf89dSDirk Eibach 84*50dcf89dSDirk Eibach if (status & STATE_TX_ERR) 85*50dcf89dSDirk Eibach printf("TX_ERR\n"); 86*50dcf89dSDirk Eibach } 87*50dcf89dSDirk Eibach 88*50dcf89dSDirk Eibach static void io_send(unsigned int fpga, unsigned int size) 89*50dcf89dSDirk Eibach { 90*50dcf89dSDirk Eibach unsigned int k; 91*50dcf89dSDirk Eibach struct io_generic_packet packet = { 92*50dcf89dSDirk Eibach .source_address = 1, 93*50dcf89dSDirk Eibach .packet_type = 1, 94*50dcf89dSDirk Eibach .packet_length = size, 95*50dcf89dSDirk Eibach }; 96*50dcf89dSDirk Eibach u16 *p = (u16 *)&packet; 97*50dcf89dSDirk Eibach 98*50dcf89dSDirk Eibach for (k = 0; k < sizeof(packet) / 2; ++k) 99*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, *p++); 100*50dcf89dSDirk Eibach 101*50dcf89dSDirk Eibach for (k = 0; k < (size + 1) / 2; ++k) 102*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, k); 103*50dcf89dSDirk Eibach 104*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, 105*50dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); 106*50dcf89dSDirk Eibach 107*50dcf89dSDirk Eibach tx_ctr++; 108*50dcf89dSDirk Eibach } 109*50dcf89dSDirk Eibach 110*50dcf89dSDirk Eibach static void io_receive(unsigned int fpga) 111*50dcf89dSDirk Eibach { 112*50dcf89dSDirk Eibach unsigned int k = 0; 113*50dcf89dSDirk Eibach u16 rx_tx_status; 114*50dcf89dSDirk Eibach 115*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 116*50dcf89dSDirk Eibach 117*50dcf89dSDirk Eibach while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { 118*50dcf89dSDirk Eibach u16 rx; 119*50dcf89dSDirk Eibach 120*50dcf89dSDirk Eibach if (rx_tx_status & STATE_RX_DATA_LAST) 121*50dcf89dSDirk Eibach rx_ctr++; 122*50dcf89dSDirk Eibach 123*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.receive_data, &rx); 124*50dcf89dSDirk Eibach 125*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 126*50dcf89dSDirk Eibach 127*50dcf89dSDirk Eibach ++k; 128*50dcf89dSDirk Eibach } 129*50dcf89dSDirk Eibach } 130*50dcf89dSDirk Eibach 131*50dcf89dSDirk Eibach static void io_reflect(unsigned int fpga) 132*50dcf89dSDirk Eibach { 133*50dcf89dSDirk Eibach u16 buffer[128]; 134*50dcf89dSDirk Eibach 135*50dcf89dSDirk Eibach unsigned int k = 0; 136*50dcf89dSDirk Eibach unsigned int n; 137*50dcf89dSDirk Eibach u16 rx_tx_status; 138*50dcf89dSDirk Eibach 139*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 140*50dcf89dSDirk Eibach 141*50dcf89dSDirk Eibach while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { 142*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]); 143*50dcf89dSDirk Eibach if (rx_tx_status & STATE_RX_DATA_LAST) 144*50dcf89dSDirk Eibach break; 145*50dcf89dSDirk Eibach 146*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 147*50dcf89dSDirk Eibach } 148*50dcf89dSDirk Eibach 149*50dcf89dSDirk Eibach if (!k) 150*50dcf89dSDirk Eibach return; 151*50dcf89dSDirk Eibach 152*50dcf89dSDirk Eibach for (n = 0; n < k; ++n) 153*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]); 154*50dcf89dSDirk Eibach 155*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, 156*50dcf89dSDirk Eibach CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); 157*50dcf89dSDirk Eibach 158*50dcf89dSDirk Eibach tx_ctr++; 159*50dcf89dSDirk Eibach } 160*50dcf89dSDirk Eibach 161*50dcf89dSDirk Eibach /* 162*50dcf89dSDirk Eibach * FPGA io-endpoint reflector 163*50dcf89dSDirk Eibach * 164*50dcf89dSDirk Eibach * Syntax: 165*50dcf89dSDirk Eibach * ioreflect {fpga} {reportrate} 166*50dcf89dSDirk Eibach */ 167*50dcf89dSDirk Eibach int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 168*50dcf89dSDirk Eibach { 169*50dcf89dSDirk Eibach unsigned int fpga; 170*50dcf89dSDirk Eibach unsigned int rate = 0; 171*50dcf89dSDirk Eibach unsigned long long last_seen = 0; 172*50dcf89dSDirk Eibach 173*50dcf89dSDirk Eibach if (argc < 2) 174*50dcf89dSDirk Eibach return CMD_RET_USAGE; 175*50dcf89dSDirk Eibach 176*50dcf89dSDirk Eibach fpga = simple_strtoul(argv[1], NULL, 10); 177*50dcf89dSDirk Eibach 178*50dcf89dSDirk Eibach /* 179*50dcf89dSDirk Eibach * If another parameter, it is the report rate in packets. 180*50dcf89dSDirk Eibach */ 181*50dcf89dSDirk Eibach if (argc > 2) 182*50dcf89dSDirk Eibach rate = simple_strtoul(argv[2], NULL, 10); 183*50dcf89dSDirk Eibach 184*50dcf89dSDirk Eibach /* enable receive path */ 185*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); 186*50dcf89dSDirk Eibach 187*50dcf89dSDirk Eibach /* set device address to dummy 1*/ 188*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.device_address, 1); 189*50dcf89dSDirk Eibach 190*50dcf89dSDirk Eibach rx_ctr = 0; tx_ctr = 0; err_ctr = 0; 191*50dcf89dSDirk Eibach 192*50dcf89dSDirk Eibach while (1) { 193*50dcf89dSDirk Eibach u16 top_int; 194*50dcf89dSDirk Eibach u16 rx_tx_status; 195*50dcf89dSDirk Eibach 196*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, top_interrupt, &top_int); 197*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 198*50dcf89dSDirk Eibach 199*50dcf89dSDirk Eibach io_check_status(fpga, rx_tx_status, true); 200*50dcf89dSDirk Eibach if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) && 201*50dcf89dSDirk Eibach (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)) 202*50dcf89dSDirk Eibach io_reflect(fpga); 203*50dcf89dSDirk Eibach 204*50dcf89dSDirk Eibach if (rate) { 205*50dcf89dSDirk Eibach if (!(tx_ctr % rate) && (tx_ctr != last_seen)) 206*50dcf89dSDirk Eibach printf("refl %llu, err %llu\n", tx_ctr, 207*50dcf89dSDirk Eibach err_ctr); 208*50dcf89dSDirk Eibach last_seen = tx_ctr; 209*50dcf89dSDirk Eibach } 210*50dcf89dSDirk Eibach 211*50dcf89dSDirk Eibach if (ctrlc()) 212*50dcf89dSDirk Eibach break; 213*50dcf89dSDirk Eibach } 214*50dcf89dSDirk Eibach 215*50dcf89dSDirk Eibach return 0; 216*50dcf89dSDirk Eibach } 217*50dcf89dSDirk Eibach 218*50dcf89dSDirk Eibach /* 219*50dcf89dSDirk Eibach * FPGA io-endpoint looptest 220*50dcf89dSDirk Eibach * 221*50dcf89dSDirk Eibach * Syntax: 222*50dcf89dSDirk Eibach * ioloop {fpga} {size} {rate} 223*50dcf89dSDirk Eibach */ 224*50dcf89dSDirk Eibach #define DISP_LINE_LEN 16 225*50dcf89dSDirk Eibach int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 226*50dcf89dSDirk Eibach { 227*50dcf89dSDirk Eibach unsigned int fpga; 228*50dcf89dSDirk Eibach unsigned int size; 229*50dcf89dSDirk Eibach unsigned int rate = 0; 230*50dcf89dSDirk Eibach 231*50dcf89dSDirk Eibach if (argc < 3) 232*50dcf89dSDirk Eibach return CMD_RET_USAGE; 233*50dcf89dSDirk Eibach 234*50dcf89dSDirk Eibach /* 235*50dcf89dSDirk Eibach * FPGA is specified since argc > 2 236*50dcf89dSDirk Eibach */ 237*50dcf89dSDirk Eibach fpga = simple_strtoul(argv[1], NULL, 10); 238*50dcf89dSDirk Eibach 239*50dcf89dSDirk Eibach /* 240*50dcf89dSDirk Eibach * packet size is specified since argc > 2 241*50dcf89dSDirk Eibach */ 242*50dcf89dSDirk Eibach size = simple_strtoul(argv[2], NULL, 10); 243*50dcf89dSDirk Eibach 244*50dcf89dSDirk Eibach /* 245*50dcf89dSDirk Eibach * If another parameter, it is the test rate in packets per second. 246*50dcf89dSDirk Eibach */ 247*50dcf89dSDirk Eibach if (argc > 3) 248*50dcf89dSDirk Eibach rate = simple_strtoul(argv[3], NULL, 10); 249*50dcf89dSDirk Eibach 250*50dcf89dSDirk Eibach /* enable receive path */ 251*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); 252*50dcf89dSDirk Eibach 253*50dcf89dSDirk Eibach /* set device address to dummy 1*/ 254*50dcf89dSDirk Eibach FPGA_SET_REG(fpga, ep.device_address, 1); 255*50dcf89dSDirk Eibach 256*50dcf89dSDirk Eibach rx_ctr = 0; tx_ctr = 0; err_ctr = 0; 257*50dcf89dSDirk Eibach 258*50dcf89dSDirk Eibach while (1) { 259*50dcf89dSDirk Eibach u16 top_int; 260*50dcf89dSDirk Eibach u16 rx_tx_status; 261*50dcf89dSDirk Eibach 262*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, top_interrupt, &top_int); 263*50dcf89dSDirk Eibach FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); 264*50dcf89dSDirk Eibach 265*50dcf89dSDirk Eibach io_check_status(fpga, rx_tx_status, false); 266*50dcf89dSDirk Eibach if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS) 267*50dcf89dSDirk Eibach io_send(fpga, size); 268*50dcf89dSDirk Eibach if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) 269*50dcf89dSDirk Eibach io_receive(fpga); 270*50dcf89dSDirk Eibach 271*50dcf89dSDirk Eibach if (rate) { 272*50dcf89dSDirk Eibach if (ctrlc()) 273*50dcf89dSDirk Eibach break; 274*50dcf89dSDirk Eibach udelay(1000000 / rate); 275*50dcf89dSDirk Eibach if (!(tx_ctr % rate)) 276*50dcf89dSDirk Eibach printf("d %lld, tx %llu, rx %llu, err %llu\n", 277*50dcf89dSDirk Eibach tx_ctr - rx_ctr, tx_ctr, rx_ctr, 278*50dcf89dSDirk Eibach err_ctr); 279*50dcf89dSDirk Eibach } 280*50dcf89dSDirk Eibach } 281*50dcf89dSDirk Eibach 282*50dcf89dSDirk Eibach return 0; 283*50dcf89dSDirk Eibach } 284*50dcf89dSDirk Eibach 285*50dcf89dSDirk Eibach U_BOOT_CMD( 286*50dcf89dSDirk Eibach ioloop, 4, 0, do_ioloop, 287*50dcf89dSDirk Eibach "fpga io-endpoint looptest", 288*50dcf89dSDirk Eibach "fpga packetsize [packets/sec]" 289*50dcf89dSDirk Eibach ); 290*50dcf89dSDirk Eibach 291*50dcf89dSDirk Eibach U_BOOT_CMD( 292*50dcf89dSDirk Eibach ioreflect, 3, 0, do_ioreflect, 293*50dcf89dSDirk Eibach "fpga io-endpoint reflector", 294*50dcf89dSDirk Eibach "fpga reportrate" 295*50dcf89dSDirk Eibach ); 296