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