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