xref: /rk3399_rockchip-uboot/test/rockchip/test-net.c (revision ded32713dc9f75f0b42296604f205fdfb9e2c149)
1 /*
2  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <fdtdec.h>
10 #include <malloc.h>
11 #include <miiphy.h>
12 #include <net.h>
13 #include <phy.h>
14 #include <asm/io.h>
15 #include "test-rockchip.h"
16 
17 #ifdef CONFIG_GMAC_ROCKCHIP
18 #define LOOPBACK_TEST_HDR_SIZE		14
19 #define LOOPBACK_TEST_DATA_SIZE		1500
20 #define LOOPBACK_TEST_FRAME_SIZE	(14 + 1500)
21 
22 #define MAX_TX_DELAY_LINE		0X7F
23 #define MAX_RX_DELAY_LINE		0X7F
24 
25 /* MAC configuration register definitions */
26 #define FRAMEBURSTENABLE		(1 << 21)
27 #define MII_PORTSELECT			(1 << 15)
28 #define FES_100				(1 << 14)
29 #define DISABLERXOWN			(1 << 13)
30 #define FULLDPLXMODE			(1 << 11)
31 
32 enum loopback_speed {
33 	LOOPBACK_SPEED_10	= 10,
34 	LOOPBACK_SPEED_100	= 100,
35 	LOOPBACK_SPEED_1000	= 1000
36 };
37 
38 extern void gmac_set_rgmii(struct udevice *dev, u32 tx_delay, u32 rx_delay);
39 
40 static struct phy_device *get_current_phydev(void)
41 {
42 	struct mii_dev *bus = mdio_get_current_dev();
43 	int i;
44 
45 	for (i = 0; i < PHY_MAX_ADDR; i++) {
46 		if (bus->phymap[i])
47 			return bus->phymap[i];
48 	}
49 
50 	return NULL;
51 }
52 
53 static void create_lbtest_frame(uchar *data, unsigned int frame_size)
54 {
55 	memset(data, 0xFF, frame_size);
56 	frame_size &= ~1;
57 	memset(data + (frame_size / 2), 0xAA, frame_size / 2 - 1);
58 }
59 
60 static void alter_lbtest_frame(uchar *data, unsigned int frame_size,
61 			       unsigned int tx, unsigned int rx)
62 {
63 	frame_size &= ~1;
64 	memset(data + (frame_size / 2 + tx), 0xBE, 1);
65 	memset(data + (frame_size / 2 + rx), 0xAF, 1);
66 }
67 
68 static int check_lbtest_frame(uchar *tx_data, uchar *rx_data,
69 			      unsigned int frame_size)
70 {
71 	int i;
72 
73 	for (i = 0; i < frame_size; i++) {
74 		if (tx_data[i] != rx_data[i])
75 			return 13;
76 	}
77 
78 	return 0;
79 }
80 
81 static void eth_setup_loopback_test(struct udevice *current, int speed)
82 {
83 	struct phy_device *phydev = get_current_phydev();
84 	struct eth_pdata *pdata = dev_get_platdata(current);
85 	u32 conf;
86 	int val;
87 
88 	if (!phydev) {
89 		printf("%s, can't get phydev\n", __func__);
90 		return;
91 	}
92 
93 	/* set mac ctrl register */
94 	conf = readl(pdata->iobase);
95 	if (speed != LOOPBACK_SPEED_1000)
96 		conf |= MII_PORTSELECT;
97 	else
98 		conf &= ~MII_PORTSELECT;
99 
100 	if (speed == LOOPBACK_SPEED_100)
101 		conf |= FES_100;
102 
103 	if (phydev->duplex)
104 		conf |= FULLDPLXMODE;
105 	writel(conf, pdata->iobase);
106 
107 	/* set phy ctrl register */
108 	val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
109 	val &= ~(BMCR_ANENABLE | BMCR_PDOWN);
110 	val |= BMCR_LOOPBACK;
111 	if (speed == LOOPBACK_SPEED_1000) {
112 		val |= BMCR_SPEED1000;
113 		val &= ~BMCR_SPEED100;
114 	} else if (speed == LOOPBACK_SPEED_100) {
115 		val &= ~BMCR_SPEED1000;
116 		val |= BMCR_SPEED100;
117 	} else if (speed == LOOPBACK_SPEED_10) {
118 		val &= ~BMCR_SPEED1000;
119 		val &= ~BMCR_SPEED100;
120 	}
121 	val |= BMCR_FULLDPLX;
122 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, val);
123 }
124 
125 static int eth_run_loopback_test(struct udevice *current, int speed, int delay_test)
126 {
127 	int flags = ETH_RECV_CHECK_DEVICE;
128 	uchar *tx_pkt, *rx_packet;
129 	int ret, length, success = 0;
130 	u32 i, j;
131 
132 	/* make sure the net_tx_packet is initialized (net_init() was called) */
133 	assert(net_tx_packet);
134 	if (!net_tx_packet)
135 		return -EINVAL;
136 
137 	net_set_ether(net_tx_packet, net_bcast_ethaddr, LOOPBACK_TEST_DATA_SIZE);
138 	tx_pkt = (uchar *)net_tx_packet + LOOPBACK_TEST_HDR_SIZE;
139 	create_lbtest_frame(tx_pkt, LOOPBACK_TEST_DATA_SIZE);
140 	udelay(50000);
141 
142 	for (i = 0x0; i < MAX_TX_DELAY_LINE; i++) {
143 		if (delay_test)
144 			printf("[0x%02x]:", i);
145 		for (j = 0x0; j < MAX_RX_DELAY_LINE; j++) {
146 			if (delay_test)
147 				gmac_set_rgmii(current, i, j);
148 
149 			alter_lbtest_frame(tx_pkt, LOOPBACK_TEST_DATA_SIZE, i, j);
150 			net_send_packet(net_tx_packet, LOOPBACK_TEST_FRAME_SIZE);
151 
152 			/*
153 			 * Make sure that mac have enough delay time to
154 			 * receive packet.
155 			 */
156 			if (speed == LOOPBACK_SPEED_10)
157 				udelay(2000);
158 			else if (speed == LOOPBACK_SPEED_100)
159 				udelay(2000);
160 			else
161 				/* The default is 1000M speed */
162 				udelay(200);
163 
164 			length = eth_get_ops(current)->recv(current, flags, &rx_packet);
165 			if (length > 0) {
166 				if (!check_lbtest_frame(net_tx_packet, rx_packet,
167 							LOOPBACK_TEST_FRAME_SIZE)) {
168 					printf("*");
169 					success++;
170 					ret = 0;
171 				} else {
172 					printf("x");
173 					ret = -EINVAL;
174 				}
175 			} else if (length == 0) {
176 				ret = -EBUSY;
177 				printf("?");
178 			} else {
179 				ret = length;
180 				printf(" ");
181 			}
182 
183 			if (length >= 0 && eth_get_ops(current)->free_pkt)
184 				eth_get_ops(current)->free_pkt(current, rx_packet,
185 							       length);
186 
187 			/* Only run loopback test once */
188 			if (!delay_test) {
189 				printf("\n");
190 				return ret;
191 			}
192 		}
193 		printf("\n");
194 	}
195 
196 	if (delay_test && success > 0)
197 		ret = 0;
198 
199 	return ret;
200 }
201 
202 static int ethernet_init(void)
203 {
204 	int ret = -EINVAL;
205 
206 	net_init();
207 	eth_halt();
208 	eth_set_current();
209 	ret = eth_init();
210 	if (ret < 0) {
211 		eth_halt();
212 		return ret;
213 	}
214 
215 	return ret;
216 }
217 
218 static int eth_loopback_test(int speed, int delay_test)
219 {
220 	struct udevice *current;
221 	int ret;
222 
223 	current = eth_get_dev();
224 	if (!current || !device_active(current))
225 		return -EINVAL;
226 
227 	eth_setup_loopback_test(current, speed);
228 	ret = ethernet_init();
229 	if (ret) {
230 		printf("%s, ethernet_init error: %d\n", __func__, ret);
231 		return ret;
232 	}
233 
234 	ret = eth_run_loopback_test(current, speed, delay_test);
235 
236 	return ret;
237 }
238 
239 static void do_eth_help(void)
240 {
241 	printf("Usage:\n");
242 	printf("rktest eth loopback speed - Test the phy loopback, speed is 1000/100/10, need to unplug the RJ45 cable\n");
243 	printf("rktest eth delaytest - Get the loopback-passed tx_delay/rx_delay array, need to unplug the RJ45 cable\n");
244 	printf("rktest eth delayline tx_delay rx_delay - Delay value is 0x00~0x7f\n");
245 	printf("rktest eth dhcp address IP:file - Boot image via network using DHCP/TFTP protocol, example: rktest eth dhcp 0x62000000 192.168.1.100:Image\n");
246 }
247 
248 int do_test_eth(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
249 {
250 	struct udevice *current;
251 	u32 tx_delay, rx_delay;
252 	char cmd_eth[512] = {0};
253 	int i, speed;
254 	int ret;
255 
256 	current = eth_get_dev();
257 	if (!current || !device_active(current))
258 		return -EINVAL;
259 
260 	switch (argc) {
261 	case 3:
262 		if (!strncmp(argv[2], "delaytest", sizeof("delaytest"))) {
263 			/* Force 1000 speed test */
264 			speed = LOOPBACK_SPEED_1000;
265 			ret = eth_loopback_test(speed, 1);
266 			return ret;
267 		} else if (!strncmp(argv[2], "help", sizeof("help"))) {
268 			do_eth_help();
269 			return 0;
270 		}
271 		break;
272 	case 4:
273 		if (!strncmp(argv[2], "loopback", sizeof("loopback"))) {
274 			speed = simple_strtoul(argv[3], NULL, 0);
275 			ret = eth_loopback_test(speed, 0);
276 			return ret;
277 		}
278 		break;
279 	case 5:
280 		if (!strncmp(argv[2], "delayline", sizeof("delayline"))) {
281 			tx_delay = simple_strtoul(argv[3], NULL, 0);
282 			rx_delay = simple_strtoul(argv[4], NULL, 0);
283 			gmac_set_rgmii(current, tx_delay, rx_delay);
284 			return 0;
285 		}
286 		break;
287 	default:
288 		break;
289 	}
290 
291 	for (i = 2; i < argc; i++) {
292 		strncat(cmd_eth, argv[i], sizeof(cmd_eth));
293 		if (i < argc - 1)
294 			strncat(cmd_eth, " ", sizeof(" "));
295 	}
296 
297 	/* run dhcp/tftp test */
298 	ret = run_command(cmd_eth, 0);
299 	if (ret < 0) {
300 		printf("DHCP test error: %d\n", ret);
301 		return ret;
302 	}
303 
304 	return 0;
305 }
306 #endif
307 
308 static cmd_tbl_t sub_cmd[] = {
309 #ifdef CONFIG_GMAC_ROCKCHIP
310 	UNIT_CMD_DEFINE(eth, 0),
311 #endif
312 };
313 
314 static const char sub_cmd_help[] =
315 #ifdef CONFIG_GMAC_ROCKCHIP
316 "    [i] rktest eth                         - test ethernet\n"
317 #else
318 ""
319 #endif
320 ;
321 
322 struct cmd_group cmd_grp_net = {
323 	.id	= TEST_ID_NET,
324 	.help	= sub_cmd_help,
325 	.cmd	= sub_cmd,
326 	.cmd_n	= ARRAY_SIZE(sub_cmd),
327 };
328