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