RK3568_Android15适配以太网网卡(gmac+phy)功能

开发背景:

开发板:正点原子ATK-DLRK3568开发板
内核:kernel-6.1
安卓系统:Android15
PHY芯片:YT8531C

项目内容

本项目内容主要是在Android15的SDK上适配正点原子的ATK-DLRK3568开发板的网卡,gmac接口+ YT8531C 这款PHY芯片。

RK3568平台有两个10M/100M/1000M 的网络MAC外设,此开发板 板载了两颗PHY芯片,PHY芯片型号为 YT8531C,Pin to Pin 兼容 RTL8211F,因此在我们的开发板上 YT8531C 和 RTL8211F 可以随意互换,今天主要来说下gmac0和gmac1搭载YT8531C这个phy组成的网卡的调试。

一、确认硬件原理图
1、先确认网卡接口

从原理图这里,可以确认开发板网卡(phy)使用的是gmac0和gmac1的接口,复位IO分别是:
gmac0复位IO(GMAC1_RSTn):GPIO2_D3
gmac1复位IO(GMAC1_RSTn):GPIO2_D1

通过查阅正点原子的资料,确认PHY芯片使用的地址是0x00,所以对应mdio总线配置的phy设备地址是0x00。

开发板使用了两个网卡设备,两个PHY芯片都是YT8531C,所以需要适配两个网卡设备,注册得到两个网卡,eth0和eth1.

2、网络硬件链路

网络链路的连接顺序是cpu(gmac0/1)出来,然后连接到PHY芯片,

3、内核适配

3.2 dts配置
主要是gmac0和gmac1的配置。
参数含义参考Documentation/devicetree/bindings/net/ethernet.txt,该文档描述了网络设备节点的一些通用属性。


&gmac0 {
	phy-mode = "rgmii";
	clock_in_out = "output";

	snps,reset-gpio = <&gpio2 RK_PD3 GPIO_ACTIVE_LOW>;
	snps,reset-active-low;
	/* Reset time is 20ms, 100ms for rtl8211f */
	snps,reset-delays-us = <0 20000 100000>;

	assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
	assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>, <&cru CLK_MAC0_2TOP>;
	assigned-clock-rates = <0>, <125000000>;

	pinctrl-names = "default";
	pinctrl-0 = <&gmac0_miim
		     &gmac0_tx_bus2
		     &gmac0_rx_bus2
		     &gmac0_rgmii_clk
		     &gmac0_rgmii_bus>;

	tx_delay = <0x24>;
	rx_delay = <0x33>;

	phy-handle = <&rgmii_phy0>;
	status = "okay";
};

&gmac1 {
	phy-mode = "rgmii";
	clock_in_out = "output";

	snps,reset-gpio = <&gpio2 RK_PD1 GPIO_ACTIVE_LOW>;
	snps,reset-active-low;
	/* Reset time is 20ms, 100ms for rtl8211f */
	snps,reset-delays-us = <0 20000 100000>;

	assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>;
	assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru CLK_MAC1_2TOP>;
	assigned-clock-rates = <0>, <125000000>;

	pinctrl-names = "default";
	pinctrl-0 = <&gmac1m1_miim
		     &gmac1m1_tx_bus2
		     &gmac1m1_rx_bus2
		     &gmac1m1_rgmii_clk
		     &gmac1m1_rgmii_bus>;

	tx_delay = <0x25>;
	rx_delay = <0x29>;

	phy-handle = <&rgmii_phy1>;
	status = "okay";
};

dts配置这里,有时候可能需要适配一下tx、rx的delay,否则可能会出现轻微的丢包,具体可以使用rk的“测tx-rx-delay补丁”,具体操作可以参考RK技术文档说明。
Rockchip_Developer_Guide_Linux_GMAC_RGMII_Delayline_CN.pdf

3.2 驱动
以太网模块的硬件相关的驱动代码主要包括 GMAC 和 PHY。其中 PHY 驱动一般使用通用 PHY 驱动,如果有需要修改特殊寄存器,请使用对应的 PHY 驱动,代码都在 drivers/net/phy目录。
这里使用的phy是裕泰微公司的芯片,型号是YT8531C,对应的驱动默认已经添加到内核目录:kernel-6.1/drivers/net/phy/motorcomm.c,只需要把编译驱动的宏定义 CONFIG_MOTORCOMM_PHY=y 打开就可。

这里简单说下PHY驱动部分内容:
打开 drivers/net/phy/motorcomm.c 文件,找到 YT8531 驱动结构体:


static struct phy_driver motorcomm_phy_drvs[] = {
        ...
        }, {
                /* same as 8511 */
                PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
                .name          = "YT8531 Gigabit Ethernet",
                .features      = PHY_GBIT_FEATURES,
                .config_init   = yt8531_config_init,
                .suspend       = genphy_suspend,
                .resume        = genphy_resume,
   ...
};

PHY_ID_YT8531 是PHY芯片的ID,定义是 0x4f51e91b。如何读取PHY id?


console:/ # cat /sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers
 0: 0x1140
 1: 0x7949
 2: 0x4f51  //0x02的值是PHY id的高四位(通用PHY寄存器)
 3: 0xe91b  //0x03的值是PHY id的低四位(通用PHY寄存器)
 4: 0x1de1
 5: 0x0
 6: 0x4
 7: 0x2801

.name表示驱动名字为“YT8531 Gigabit Ethernet”,系统启动过程中,加载网卡设备驱动时候就会提示PHY驱动文字为“YT8531 Gigabit Ethernet”。
yt8531_config_init是PHY芯片初始化的接口,对PHY进行一些初始化的操作,在这个接口里面,会通过mdio接口进行一些寄存器的初始化设置操作。

4、PHY寄存器读写调试

/sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers

写寄存器,例如往 Reg0 写入 0xab01,
echo 0x00 0xab01 > /sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers

读寄存器:
cat /sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers

这个读命令会读取 0~31 的所有寄存器,所以可以查看对应的寄存器值。
比如设置YT8531的寄存器,如果要设置0xa001寄存器值(0xa001为ext 寄存器,所以需要先将寄存器0xa001写入0x1e,再去读写0x1f,这是裕泰微的ext寄存器的读写方式),其他正常的寄存器按照正常读写即可,比如0x02和0x03是读取PHY id的通用寄存器,直接正常读写即可。当然,不同的PHY可能读写读写方式不一样,需要具体情况而定,比如RTL也有自己的读写方式。

5、MAC地址

5.1随机mac地址
随机mac地址是由驱动随机生成,每次重启设备mac地址会改变。
对应驱动代码:drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
eth_hw_addr_random(priv->dev); //获取随机mac地址
5.2 固定mac地址
固定mac地址使用烧写在IDB或vendor Storage中的mac地址,或者外接的eeprom设备中保存的mac地址,如果获取到保存的地址不符合规范,则会使用驱动随机生成的mac地址。

6、常见问题分析

6.1 网卡已经注册了,tx和rx也有数据,设置了IP地址但是ping不通网络(同网段的ip或者网关)
问题现象:进入“设置”->“网络和互联网”->“Ethernet”->“Ethernet Ip mode”,选择static,即设置静态ip模式,然后设置ip、掩码、网关和dns,然后去ping同网段的ip地址,ping不通,设置dhcp也获取不到IP。


console:/ # ifconfig eth0                                                      
eth0      Link encap:Ethernet  HWaddr d6:aa:45:72:86:81  Driver rk_gmac-dwmac
          inet addr:192.168.1.10  Bcast:192.168.1.255  Mask:255.255.255.0 
          inet6 addr: fe80::9e05:95e4:d2e7:b9b2/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10010 errors:0 dropped:5 overruns:0 frame:0 
          TX packets:424 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:602304 TX bytes:26694 
          Interrupt:44 

console:/ # ping 192.168.1.9
PING 192.168.1.9 (192.168.1.9) 56(84) bytes of data.
From 192.168.1.10: icmp_seq=1 Destination Host Unreachable
From 192.168.1.10: icmp_seq=2 Destination Host Unreachable
From 192.168.1.10: icmp_seq=3 Destination Host Unreachable

分析解决:

经过查阅原理图和YT8531的规格书资料,发现该问题跟phy模式的配置电压有关,只需要注意配置phy的电压为1.8V。dts默认配置成3.3v了,导致模式不对,网络不通。

YT8531规格书也有相关说明:
图片[1] - RK3568_Android15适配以太网网卡(gmac+phy)功能 - 鹿快
原理图部分:
图片[2] - RK3568_Android15适配以太网网卡(gmac+phy)功能 - 鹿快
dts配置修改按照如下改动:


&pmu_io_domains {
    vccio4-supply = <&vcc_1v8>;
    vccio6-supply = <&vcc_1v8>;
};

改完之后,更新boot.img,就可以ping通网关了。


console:/ # ifconfig eth0                                                    
eth0  Link encap:Ethernet HWaddr d2:aa:45:72:86:81 Driver rk_gmac-dwmac
      inet addr:192.168.1.128 Bcast:192.168.1.255  Mask:255.255.255.0 
          inet6 addr: fe80::4215:cd4b:4b1a:dae7/64 Scope: Link
          inet6 addr: 2409:8a56:3226:a680:bdbe:4161:acef:e16/64 Scope: Global
          inet6 addr: 2409:8a56:3226:a680:253b:de1b:5b63:4edd/64 Scope: Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:797 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:243 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:57924 TX bytes:46380 
          Interrupt:44 
console:/ # ping 192.168.1.1                                                   
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.91 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.95 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=1.92 ms
^C
--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 1.914/1.929/1.951/0.015 ms
console:/ # 
console:/ # ping www.baidu.com                                                 
PING www.a.shifen.com (183.240.99.58) 56(84) bytes of data.
64 bytes from 183.240.99.58: icmp_seq=1 ttl=54 time=11.4 ms
64 bytes from 183.240.99.58: icmp_seq=2 ttl=54 time=11.1 ms
64 bytes from 183.240.99.58: icmp_seq=3 ttl=54 time=11.3 ms
64 bytes from 183.240.99.58: icmp_seq=4 ttl=54 time=12.1 ms

6.2 DMA Initialization Failed
如果 GMAC 的驱动开机 log 上出现打印: DMA engine initialization failed ,可以认为是 GMAC的工作时钟出问题了。先使用示波器测量时钟引脚是否有时钟,时钟频率以及幅度等指标是否正常,主要确认以下几个方面:
(1)IOMUX 出错,检查时钟脚寄存器值是否正确;
(2)时钟方向以及配置与硬件不匹配;
(3)检查 clock tree 和 CRU 寄存器,确认时钟频率大小和时钟是否有使能。

6.3 PHY初始化失败
如果 GMAC 的驱动开机log上出现打印:No PHY found 或者 Cannot attach to PHY,表示找不到 PHY。驱动会通过MDIO先读取PHY的ID,可以测量MDC和 MDIO波形,波形是否正常,该总线类似于I2C,MDC 频率要求是小于 2.5M。一般来说,找不到 PHY 有以下几个原因:
(1)检查 MDC/MDIO IOMUX 寄存器值是否正确
(2)PHY 供电是否正常
(3)Reset IO 配置不正确,Reset IO 时序不满足 PHY datasheet 要求,不同 PHY 的时序要求不一致。
(4)测试 MDIO/MDC 波形是否异常,其中 MDC 时钟频率要求小于 2.5M
(5)若log中出现 MDIO device at address 1 is missing.类似的打印,则表明phy硬件address跟软件不匹配导致。建议修改成通⽤⼴播地址。


&mdio0 {
rgmii_phy0: phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x0>;
};
};

6.4 网络不断出现 Link up/Link down
如果出现了 Link 问题,有个排除法,即将 MDC/MDIO 与主控断开,与电脑直连,查看电脑端是否有同样的问题,以此排除软件上的干扰,那么需要重点排查下硬件上的影响,先测试 TXN/P 以及 RXN/P 是否有 Link 波形。

6.5 网口状态灯不对
在PHY驱动kernel-6.1/drivers/net/phy/motorcomm.c修改,通过寄存器去控制对应的网口状态灯,具体查询PHY规格书或者咨询PHY芯片FAE工程师,我这里是参考正点原子已经适配好的驱动(移植安卓13的SDK驱动的内容,即下面所示带加号的内容,仅供参考)


+#define YT8531_EXTREG_LED0             0xa00c
+#define YT8531_EXTREG_LED1             0xa00d
+#define YT8531_EXTREG_LED2             0xa00e


+static int yt8531_led_init(struct phy_device *phydev)
+{
+       int ret = -1;
+
+       /* 千兆网口绿色LED灯: 运行模式为1000Mbps时点亮 */
+       ret = ytphy_write_ext(phydev, YT8531_EXTREG_LED1, 0x40);
+       if (ret < 0)
+               return ret;
+
+       /* 千兆网口黄色LED灯: 当phy链路通并且TX/RX处于活动状态时闪烁 */
+       return ytphy_write_ext(phydev, YT8531_EXTREG_LED2, 0x2600);
+}
+
 static int yt8531_config_init(struct phy_device *phydev)
 {
        int ret = 0, val;
@@ -1165,22 +786,11 @@ static int yt8531_config_init(struct phy_device *phydev)
        if (ret < 0)
                return ret;

-       return ret;
+       return yt8531_led_init(phydev);
 }

6.6 以太网网速测试
用两张卡连接到网线,配置同网段的IP,注意:这里要连接千兆路由器或者千兆交换机,没有这两个设备可以开发板和电脑直接连接。

这里我仅使用 iperf3 工具测试开发板上网口的带宽,其它的一些参数特性就不给大家进行详
细测试了。
iperf3 的测试方法需要有一台主机作为服务器端,另一台主机作为客户端,客户端向服务
器端发送数据,这里我们可以将 Ubuntu 系统作为服务器端,而开发板作为客户端进行测试。
在 ubuntu 系统中执行下面这条命令,将 ubuntu 系统作为 iperf3 的服务器,如下所示:


iperf3 -s -i 1

-s 表示将其作为服务端。
接下来我们需要在开发板终端执行下面这条命令,将开发板作为客户端,并进行测试:


iperf3 -c 192.168.1.148 -i 1 -t 999

-c 选项表示将其作为客户端,后面紧跟着的就是服务器主机的 IP 地址;
-i 是指周期性吞吐量报告之间的秒数;
-t是测试测试时间,单位是s

正常千兆网卡测试出来发送和接收带宽分别为 935M左右,基本接近 1000M 的带
宽,说明千 M 网络工作正常。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
大河网的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容