xref: /rk3399_rockchip-uboot/board/gdsys/common/cmd_ioloop.c (revision 50dcf89d90b3597d86f5d26f131eabc98bbd5209)
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