Linux-PHY 88E1512 驱动调试记录

1. 简介

1)开发板平台:创龙 AM5728 (tl5728-easy-evm)
2)PHY芯片:Marvell 88E1512

88E1512和88E1510都是一个系列的phy,采用marvell的通用phy驱动,驱动源码路径如下:drivers/net/phy/marvell.c

2. 应用场景

1)系统框图
Linux-PHY 88E1512 驱动调试记录_第1张图片
AM5728连接两个PHY,PHY0的工作模式是 RGMII to Copper (RGMII到电口),PHY1的工作模式是 RGMII to SGMII。
两个PHY与处理器的连接方式都是RGMII,只是PHY出口的电气接口不一样,一个到电口,一个到SGMII与交换芯片相连。

2)硬件原理图:
LAN0
Linux-PHY 88E1512 驱动调试记录_第2张图片
LAN1

Linux-PHY 88E1512 驱动调试记录_第3张图片

3. 芯片手册

PHY的工作模式:(P5)
Linux-PHY 88E1512 驱动调试记录_第4张图片
几种电气接口的解释:(P33)
MDI:传输媒介接口
RGMII:系统接口
SGMII:系统接口/传输媒介接口
Linux-PHY 88E1512 驱动调试记录_第5张图片
在这里插入图片描述
PHY的工作模式选择:Page 18 – Register 20
Linux-PHY 88E1512 驱动调试记录_第6张图片
Linux-PHY 88E1512 驱动调试记录_第7张图片
寄存器读写的API:
Linux-PHY 88E1512 驱动调试记录_第8张图片
读写88E1512的寄存器前,先往Register 22写入要操作的 Page number。我们这里要操作的是 Page 18,Register 20,用于配置PHY的工作模式MODE[2:0]

在这里插入图片描述
Linux-PHY 88E1512 驱动调试记录_第9张图片

4. 修改的地方

1)设备树 (创龙)

AM57xx\Linux-RT\kernel\Linux-RT-4.9.65\arch\arm\boot\dts\am57xx-beagle-x15-common.dtsi

Linux-PHY 88E1512 驱动调试记录_第10张图片
Linux-PHY 88E1512 驱动调试记录_第11张图片

phy-mode属性是“rgmii-id”, “rgmii-id”和“rgmii”是有区别的,主要体现在RX和TX的延时是由MAC补偿还是由PHY补偿。如下:
(参考:http://www.360doc.com/content/19/0804/20/36367108_852988840.shtml

Linux-PHY 88E1512 驱动调试记录_第12张图片
内核文档
AM57xx\Linux-RT\kernel\Linux-RT-4.9.65\Documentation\devicetree\bindings\net\ethernet.txt

对 phy-mode 属性进行了详细介绍,可以阅读查看。

上面的3个节点未做修改,创龙底板使用的PHY是KSZ9031(RGMII to Copper),沿用了这3个节点的属性。

2)驱动源码修改
AM57xx\Linux-RT\kernel\Linux-RT-4.9.65\drivers\net\phy\marvell.c

主要是修改了初始化函数:m88e1510_config_init(),根据设备树中的 operating-mode 属性来判断PHY的工作模式,以此来写寄存器的值。
在这里插入图片描述

/* add by heat */
static int m88e1510_config_init(struct phy_device *phydev)
{
    int err;
    int temp;
    u32 mode_num;

    int ret;
    struct device_node *np = phydev->mdio.dev.of_node;

    ret = of_property_read_u32(np, "operating-mode", &mode_num);

    if (ret) {
        printk("invalid 'operating-mode' property: %d\n", ret);
        return ret;     
    } else {
        if (0 == mode_num ) {
            /* RGMII-to-Copper mode initialization */
            printk("=== Enter RGMII-to Copper mode initialization. === \n");
            if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
                /* Select page 18 */
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
                if (err < 0)
                    return err;

                /* In reg 20, write MODE[2:0] = 0x0 (RGMII to Copper) */
                temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
                temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
                temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_TO_COPPER; 
                err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
                if (err < 0)
                    return err;

                /* PHY reset is necessary after changing MODE[2:0] */
                temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
                err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
                if (err < 0)
                    return err;

                /* heat test */
                /* Select page 18 */
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
                if (err < 0)
                    return err;
                /* read reg 22 */
                temp = phy_read(phydev, MII_MARVELL_PHY_PAGE);
                printk("=== ETH0: Reg22 : 0x%x . === \n", temp);

                /* In reg 20, write MODE[2:0] = 0x0 (RGMII to Copper) */
                temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
                printk("=== ETH0: Reg20_Page18 : 0x%x . === \n", temp);
    
                /* Reset page selection */
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
                if (err < 0)
                    return err;

            }
        } else if (2 == mode_num) {
            /* RGMII-to-1000BASE-X mode initialization */
            printk("=== Enter RGMII-to-1000BASE-X mode initialization. === \n");
            if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
                /* Select page 18 */
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
                if (err < 0)
                    return err;

                /* In reg 20, write MODE[2:0] = 0x4 (RGMII to SGMII) */
                temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
                temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
                temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_TO_1000BASE_X;    /* RGMII-to-1000BASE-X */
                err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
                if (err < 0)
                    return err;

                /* PHY reset is necessary after changing MODE[2:0] */
                temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
                err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
                if (err < 0)
                    return err;

                /* heat test */
                /* Select page 18 */
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
                if (err < 0)
                    return err;
                /* read reg 22 */
                temp = phy_read(phydev, MII_MARVELL_PHY_PAGE);
                printk("=== ETH1: Reg22 : 0x%x . === \n", temp);

                temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
                printk("=== ETH1: Reg20_Page18 : 0x%x . === \n", temp); 

            }
        }
    }

    return m88e1121_config_init(phydev);
}
/* End add by heat */

其他地方暂未修改。

3)文件系统修改

    上面的驱动在内核加载后,网卡eth0是电口,插上网线后直接phy0显示link up; 网卡eth1与交换芯片P9口连接,eth1可以看做是Fiber口,但是PHY并没有切至Fiber Page,MAC一直获取的是PHY的CopperPage的link状态,所以网卡eth1一直显示无法link。我们使用mdio 工具进行了切页,将PHY切至Fiber Page后,网卡link up;

文件路径: \etc\init.d\init-fatri
添加的命令如下
在这里插入图片描述
mdio eth1 22 1 用于切至Fiber Page,以便MAC正确判断PHY1的link状态;

mdio eth1 22 3;mdio eth1 16 0xa0 用于配置LED[1]的工作模式。

硬件设计时,PHY1的LED[1]引脚还用于接收PPS信号输入。在测试时发现该引脚会影响PPS信号质量,会拉低PPS信号电平。需操作PHY寄存器 LED[1]的工作模式为Hi-Z高阻状态。

Linux-PHY 88E1512 驱动调试记录_第13张图片

寄存器配置:

Linux-PHY 88E1512 驱动调试记录_第14张图片
此外,还有一项重要更改:
Linux-PHY 88E1512 驱动调试记录_第15张图片
关闭AM5728 RGMII-1 内部时延补偿。因为我们使用的是 rgmii-id 模式,由 88E1512 PHY侧补偿 rgmii 的TX和RX时延,就不用MAC再进行补偿,所以应该关闭AM5728 MAC侧的时延补偿。

AM5728的手册:Page-4305 ,如下图所示。
Table 18-279. CTRL_CORE_SMA_SW_1
Linux-PHY 88E1512 驱动调试记录_第16张图片

5. PHY调试心得

1) PHY 一般都有 Packet Generation 功能,可以通过此功能判断 PHY到Copper端的链路是否正常。

Linux-PHY 88E1512 驱动调试记录_第17张图片
Linux-PHY 88E1512 驱动调试记录_第18张图片
开发板与PC机直连,PC机打开Wireshark抓包,看是否可以抓到固定大小的包(5AA55AA5…)。
开发板可以打开 tcpdump 工具,由PC机ping 开发板,这样链路就是copper->PHY->MAC,通过 tcpdump抓包;
tcpdump命令:“tcpdump –i eth0 arp –XX -v”,抓ARP解析包,看能否收到。

2) PHY和MAC一般都具备CRC 统计功能,可以统计收发的数据包个数以及错包个数,以此来判断哪个方向的传输不正常。

Linux-PHY 88E1512 驱动调试记录_第19张图片
Linux-PHY 88E1512 驱动调试记录_第20张图片
其他参考文件:

头文件:
AM57xx\Linux-RT\kernel\Linux-RT-4.9.65\include\linux\marvell_phy.h
AM57xx\Linux-RT\kernel\Linux-RT-4.9.65\include\linux\phy.h

你可能感兴趣的:(网卡驱动)