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