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