IMX6ULL-Linux6.3.5版本网卡调试深入讲解
目录
2.ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1
接着上一章移植Linux 6.3.5系统到imx6ull开发板 ,现在我们来讲解一下Linux下网卡调试
一、先来了解一下imx6ull的网络节点的如何定义的
首先找到 imx6ull 开发板设备树文件 imx6ull-toto.dts,打开文件内容如下:
#include "imx6ull.dtsi"
#include "imx6ul-14x14-evk.dtsi"
/ {
model = "Freescale i.MX6 UltraLiteLite 14x14 EVK Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
};
&clks {
assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>;
assigned-clock-rates = <320000000>;
};
从上面可以看出,包含两个.dtsi文件,下面我就从这两个dtsi文件中找到fec节点的定义。
最终在imx6ul.dtsi文件找到关于fec节点的定义,如下:
fec1: ethernet@2188000 {
compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
reg = <0x02188000 0x4000>;
interrupt-names = "int0", "pps";
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ENET>,
<&clks IMX6UL_CLK_ENET_AHB>,
<&clks IMX6UL_CLK_ENET_PTP>,
<&clks IMX6UL_CLK_ENET_REF>,
<&clks IMX6UL_CLK_ENET_REF>;
clock-names = "ipg", "ahb", "ptp",
"enet_clk_ref", "enet_out";
fsl,num-tx-queues = <1>;
fsl,num-rx-queues = <1>;
fsl,stop-mode = <&gpr 0x10 3>;
fsl,magic-packet;
status = "disabled";
};
fec2: ethernet@20b4000 {
compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
reg = <0x020b4000 0x4000>;
interrupt-names = "int0", "pps";
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ENET>,
<&clks IMX6UL_CLK_ENET_AHB>,
<&clks IMX6UL_CLK_ENET_PTP>,
<&clks IMX6UL_CLK_ENET2_REF_125M>,
<&clks IMX6UL_CLK_ENET2_REF_125M>;
clock-names = "ipg", "ahb", "ptp",
"enet_clk_ref", "enet_out";
fsl,num-tx-queues = <1>;
fsl,num-rx-queues = <1>;
fsl,stop-mode = <&gpr 0x10 4>;
fsl,magic-packet;
status = "disabled";
};
在imx6ull-14x14-evk.dtsi文件中看到fec节点其他属性的定义,如下:
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-supply = <®_peri_3v3>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-supply = <®_peri_3v3>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-id0022.1560";
reg = <2>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-id0022.1560";
reg = <1>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = "rmii-ref";
};
};
};
二、使用默认网卡配置
首先我们使用默认配置编译出来的zImage和dtb文件启动后,查看一下网络是怎么样的;
1.启动以后使用“ifconfig”命令查看一下当前活动的网卡有哪些,串口打印信息如下:
/ # ifconfig
/ #
可以看出,当前没有活动的网卡。
2.输入命令“ifconfig -a”来查看一下开发板中存在的所有网卡,串口打印信息如下:
/ # ifconfig -a
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:220
can1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:221
eth0 Link encap:Ethernet HWaddr A2:CB:A7:D7:6A:FC
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 32:34:46:78:9A:DC
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
LOOPBACK MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
sit0 Link encap:IPv6-in-IPv4
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
其中 can0 和 can1 为 CAN 接口的网卡, eth0 和 eth1 才是网络接口的网卡,其中eth0 对应于 ENET2, eth1 对应于 ENET1。
使用如下命令依次打开 eth0 和 eth1 这两个网卡:
/ # ifconfig eth0 up
[ 234.350880] Micrel KSZ8081 or KSZ8091 20b4000.ethernet-1:01: phy_poll_reset failed: -110
[ 234.359299] fec 20b4000.ethernet eth0: Unable to connect to phy
ifconfig: SIOCSIFFLAGS: No such device
/ # ifconfig eth1 up
[ 247.631114] Micrel KSZ8081 or KSZ8091 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 247.639560] fec 2188000.ethernet eth1: Unable to connect to phy
ifconfig: SIOCSIFFLAGS: No such device
从上面可以看到eth0和eth1当前默认使用的是Micrel KSZ8081类型的phy,而我们的开发板imx6ull使用的是SMSC的LAN8720,因此修改使用phy类型为SMSC。
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-id0022.1560";
reg = <2>;
micrel,led-mode = <1>;
...
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-id0022.1560";
reg = <1>;
micrel,led-mode = <1>;
...
};
其中,
compatible: 兼容性列表,一般为“ethernet-phy-ieee802.3-c22”或“ethernet-phy-ieee802.3-c45”,分别对应 IEEE802.3 的 22 簇和 45 簇,默认是 22 簇。
也可以设置为其他值,如果 PHY的 ID 不知道的话可以 compatible 属性可以设置为“ethernet-phy-idAAAA.BBBB”, AAAA 和BBBB 的含义如下:
- AAAA: PHY 的 16 位 ID 寄存器 1 值,也就是 OUI 的 bit3~18, 16 进制格式。
- BBBB: PHY 的 16 位 ID 寄存器 2 值,也就是 OUI 的 bit19~24, 16 进制格式。
compatible = "ethernet-phy-id0022.1560"; 表明对应phy-id为0x00221560
“micrel,led-mode = <1>;”表明 PHY 芯片是 MICREL 公司的。
结合,上面的 "compatible" 属性中的phy-id和 "micrel",可以得出 Linux内核默认使用的是 MICREL 公司的 PHY 芯片 KSZ8081。
在driver/net/phy/micrel.c再次验证PHY 芯片 KSZ8081。
{
.phy_id = PHY_ID_KSZ8081,
.name = "Micrel KSZ8081 or KSZ8091",
.phy_id_mask = MICREL_PHY_ID_MASK,
.flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
.driver_data = &ksz8081_type,
.probe = kszphy_probe,
.config_init = ksz8081_config_init,
.soft_reset = genphy_soft_reset,
.config_aneg = ksz8081_config_aneg,
.read_status = ksz8081_read_status,
.config_intr = kszphy_config_intr,
.handle_interrupt = kszphy_handle_interrupt,
.get_sset_count = kszphy_get_sset_count,
.get_strings = kszphy_get_strings,
.get_stats = kszphy_get_stats,
.suspend = kszphy_suspend,
.resume = kszphy_resume,
.cable_test_start = ksz886x_cable_test_start,
.cable_test_get_status = ksz886x_cable_test_get_status,
},
其中宏PHY_ID_KSZ8081,定义如下:
/* same id: KS8081, KS8091 */
#define PHY_ID_KSZ8081 0x00221560
这个数字是不是很熟悉?没错他就是上面"compatible" 属性中的phy-id。说明我们上面的推理是完全正确的。
那么修改为我们自己开发板的SMSC的LAN8720,具体修改如下:
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-id0007.c0f0";
reg = <2>;
smsc,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-id0007.c0f0";
reg = <1>;
smsc,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = "rmii-ref";
};
其中phy-id的具体数值0007.c0f0,可以在driver/net/phy/smsc.c文件中查看到,如下:
{
/* This covers internal PHY (phy_id: 0x0007C0F0) for
* LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)
*/
.phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8710/LAN8720",
/* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
/* basic functions */
.read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init,
.soft_reset = smsc_phy_reset,
.config_aneg = lan95xx_config_aneg_ext,
/* IRQ related */
.config_intr = smsc_phy_config_intr,
.handle_interrupt = smsc_phy_handle_interrupt,
/* Statistics */
.get_sset_count = smsc_get_sset_count,
.get_strings = smsc_get_strings,
.get_stats = smsc_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
}, {
修改后,编译,下载验证,打印信息如下:
/ # ifconfig eth0 192.168.0.122 up
[ 89.870922] SMSC LAN8710/LAN8720 20b4000.ethernet-1:01: phy_poll_reset failed: -110
[ 89.878889] fec 20b4000.ethernet eth0: Unable to connect to phy
ifconfig: SIOCSIFFLAGS: No such device
/ #
/ # ifconfig eth1 192.168.0.123 up
[ 92.355687] SMSC LAN8710/LAN8720 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 92.363699] fec 2188000.ethernet eth1: Unable to connect to phy
ifconfig: SIOCSIFFLAGS: No such device
现在,网络使用的是SMSC LAN8720phy芯片了,但是phy_poll_reset failed,现在首先查一下phy复位管脚定义。
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-supply = <®_peri_3v3>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-supply = <®_peri_3v3>;
status = "okay";
}
从上面可以看到,fec1和fec2两个节点都没有定义phy复位管脚,但是在linux内核源码中driver/net/ethernet/freescale/fec_main.c文件中fec_probe函数中调用了fec_reset_phy,而fec_reset_phy中会要求到phy reset管脚,fec_reset_phy具体内容如下:
static int fec_reset_phy(struct platform_device *pdev)
{
struct gpio_desc *phy_reset;
int msec = 1, phy_post_delay = 0;
struct device_node *np = pdev->dev.of_node;
int err;
if (!np)
return 0;
err = of_property_read_u32(np, "phy-reset-duration", &msec);
/* A sane reset duration should not be longer than 1s */
if (!err && msec > 1000)
msec = 1;
err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay);
/* valid reset duration should be less than 1s */
if (!err && phy_post_delay > 1000)
return -EINVAL;
phy_reset = devm_gpiod_get_optional(&pdev->dev, "phy-reset",
GPIOD_OUT_HIGH);
if (IS_ERR(phy_reset))
return dev_err_probe(&pdev->dev, PTR_ERR(phy_reset),
"failed to get phy-reset-gpios\n");
if (!phy_reset)
return 0;
if (msec > 20)
msleep(msec);
else
usleep_range(msec * 1000, msec * 1000 + 1000);
gpiod_set_value_cansleep(phy_reset, 0);
if (!phy_post_delay)
return 0;
if (phy_post_delay > 20)
msleep(phy_post_delay);
else
usleep_range(phy_post_delay * 1000,
phy_post_delay * 1000 + 1000);
return 0;
}
其中,复位时间从设备树中“phy-reset-duration”属性信息获取。复位管脚 IO 从设备树中“phy-reset-gpios”属性信息获取。
下面,设备树fec节点中添加 “phy-reset-gpios” 和 “phy-reset-duration” 属性:
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-supply = <®_peri_3v3>;
phy-reset-duration = <200>;
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-supply = <®_peri_3v3>;
phy-reset-duration = <200>;
phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
status = "okay";
}
继续,编译,烧写,验证,具体打印信息如下:
[ 1.550883] spi-nor spi4.0: unrecognized JEDEC id bytes: ff ff ff ff ff ff
[ 1.559110] spi-4 uses legacy gpio name 'gpio-mosi' instead of 'mosi-gpios'
[ 1.566319] spi-4 uses legacy gpio name 'gpio-sck' instead of 'sck-gpios'
[ 1.575705] gpio-161 (eth0-phy): hogged as output/high
[ 1.581127] gpio-162 (eth1-phy): hogged as output/high
[ 1.592443] CAN device driver interface
[ 1.600173] fec 20b4000.ethernet: error -EBUSY: failed to get phy-reset-gpios
[ 1.607445] fec: probe of 20b4000.ethernet failed with error -16
[ 1.616543] fec 2188000.ethernet: error -EBUSY: failed to get phy-reset-gpios
[ 1.624008] fec: probe of 2188000.ethernet failed with error -16
可以看到"gpio-161 (eth0-phy): hogged as output/high","fec 20b4000.ethernet: error -EBUSY: failed to get phy-reset-gpios",说明这个复位管脚被其他外设复用为其他功能了。接下来,在设备树文件中查找gpio5的7和8管脚复用情况。
查看fec1、2的复位管脚是否存在复位为其他设备的,在imx6ull-14x14-evk.dtsi文件中spi-4节点有使用,下面屏蔽该节点下的管脚。
spi-4 {
compatible = "spi-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi4>;
status = "okay";
gpio-sck = <&gpio5 11 0>;
gpio-mosi = <&gpio5 10 0>;
/*
cs-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
*/
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
gpio_spi: gpio@0 {
compatible = "fairchild,74hc595";
gpio-controller;
#gpio-cells = <2>;
reg = <0>;
registers-number = <1>;
spi-max-frequency = <100000>;
/*
enable-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
*/
};
};
pinctrl_spi4: spi4grp {
fsl,pins = <
MX6UL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
MX6UL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
/*
MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000
*/
>;
};
编译,烧写,验证,串口启动打印信息如下:
[ 1.784350] fec 20b4000.ethernet: Invalid MAC address: 00:00:00:00:00:00
[ 1.791232] fec 20b4000.ethernet: Using random MAC address: ea:69:9c:3a:f5:4c
[ 1.805714] fec 20b4000.ethernet eth0: registered PHC device 0
[ 2.028968] pps pps1: new PPS source ptp1
[ 2.165778] fec 2188000.ethernet eth1: registered PHC device 1
使用"ifconfig eth0 192.168.0.122 up",查看能否网卡ip设置成功,打印如下:
/ # ifconfig eth0 192.168.0.122 up
[ 210.770925] SMSC LAN8710/LAN8720 20b4000.ethernet-1:01: attached PHY driver (mii_bus:phy_addr=20b4000.ethernet-1:01, irq=POLL)
/ # [ 213.931275] fec 20b4000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
[ 213.939492] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
/ #
/ # ping 192.168.0.106
PING 192.168.0.106 (192.168.0.106): 56 data bytes
64 bytes from 192.168.0.106: seq=0 ttl=64 time=5.396 ms
64 bytes from 192.168.0.106: seq=1 ttl=64 time=4.194 ms
^C
--- 192.168.0.106 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 4.194/4.795/5.396 ms
/ # ifconfig eth1 192.168.0.123 up
[ 292.900810] SMSC LAN8710/LAN8720 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 292.909579] fec 2188000.ethernet eth1: Unable to connect to phy
从上面可以看到,eth0对应FEC2已经设置网卡成功,并且能成功ping通PC电脑。而eth1对应FEC1复位还是失败。但是我们一眼可发现ethernet-1:02的phy地址为2,这里与我们开发板原理图上fec1的phy地址为0给的不一致,因此修改fec1节点对应的phy地址,修改如下:
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-id0022.1560";
reg = <0>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
修改后,下载验证,串口打印如下:
/ # ifconfig eth1 192.168.0.123 up
[ 292.900810] SMSC LAN8710/LAN8720 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 292.909579] fec 2188000.ethernet eth1: Unable to connect to phy
eth1对应FEC1复位还是失败。
三、查找eth1对应FEC1复位失败原因
尝试方法
1.修改smsc_phy_reset函数
查找资料,看到正点原子的一篇文章里有说“LAN8720A的驱动文件是drivers/net/phy/smsc.c,smsc_phy_reset的函数只有PHY处于powerdown模式的时候第70~83行的代码段才会执行。
向LAN872A0的BMCR寄存器写入BMCR_RESET,也就是对LAN8720A进行软件初始化,所以smsc_phy_reset函数会对LAN8720A进行软件初始化。
看到没,只有LAN8720A处于powerdown模式的时候才会对LAN8720A进行软复位,但是我们在uboot中已经“唤醒”了LAN8720A,LAN8720A也已经工作了,因此它不可能处于powerdown模式,进而就没法对LAN8720A进行软复位。
因此,我们要对smsc_phy_reset函数函数进行修改,将复位相关的代码从条件语句中提出来,不管LAN8720A有没有工作在powerdown模式下,只要调用smsc_phy_reset函数就对LAN8720A进行软复位”。
修改后的smsc_phy_reset函数内容如下:
static int smsc_phy_reset(struct phy_device *phydev)
{
int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
if (rc < 0)
return rc;
/* If the SMSC PHY is in power down mode, then set it
* in all capable mode before using it.
*/
if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
/* set "all capable" mode */
rc |= MII_LAN83C185_MODE_ALL;
phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
}
/*add line*/
phy_write(phydev, MII_BMCR, BMCR_RESET);
/* reset the phy */
return genphy_soft_reset(phydev);
}
修改后编译下载,串口打印如下:
/ # ifconfig eth1 192.168.0.123 up
[ 292.900810] SMSC LAN8710/LAN8720 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 292.909579] fec 2188000.ethernet eth1: Unable to connect to phy
2.ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1
还要资料说“如果要在I.MX6ULL上使用LAN8720A就需要设置ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1。”
要在I.MX6ULL上使用LAN8720A,需要修改一下Linux内核源码,打开drivers/net/ethernet/freescale/fec_main.c,找到函数fec_probe,在fec_probe中加入如下代码:
static int
fec_probe(struct platform_device *pdev)
{
struct fec_enet_private *fep;
struct fec_platform_data *pdata;
phy_interface_t interface;
struct net_device *ndev;
int i, irq, ret = 0;
const struct of_device_id *of_id;
static int dev_id;
struct device_node *np = pdev->dev.of_node, *phy_node;
int num_tx_qs;
int num_rx_qs;
char irq_name[8];
int irq_cnt;
struct fec_devinfo *dev_info;
/* 设置 MX6UL_PAD_ENET1_TX_CLK 和 MX6UL_PAD_ENET2_TX_CLK
* 这两个 IO 的复用寄存器的 SION 位为 1。
*/
void __iomem *IMX6U_ENET1_TX_CLK;
void __iomem *IMX6U_ENET2_TX_CLK;
IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
writel(0X14, IMX6U_ENET1_TX_CLK);
IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
writel(0X14, IMX6U_ENET2_TX_CLK);
......
修改验证,串口打印如下:
/ # ifconfig eth1 192.168.0.123 up
[ 292.900810] SMSC LAN8710/LAN8720 20b4000.ethernet-1:02: phy_poll_reset failed: -110
[ 292.909579] fec 2188000.ethernet eth1: Unable to connect to phy
3.读取phy寄存器
现在没有什么方法,就只有采用最原始也是最有效的方法,那就是添加打印定位法。
首先我们来在phy复位之前读一下phy寄存器1,2,3,看能不能读取phy寄存器1,2,3正确的值,添加如下代码:
static int smsc_phy_reset(struct phy_device *phydev)
{
int rv = 0;
int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
if (rc < 0)
return rc;
printk("smsc_phy_reset\n");
rv = phy_read(phydev, 1);
printk("rv 1:0x%x\n", rv);
rv = phy_read(phydev, 2);
printk("rv 2:0x%x\n", rv);
rv = phy_read(phydev, 3);
printk("rv 3:0x%x\n", rv);
/* If the SMSC PHY is in power down mode, then set it
* in all capable mode before using it.
*/
if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
/* set "all capable" mode */
rc |= MII_LAN83C185_MODE_ALL;
phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
}
phy_write(phydev, MII_BMCR, BMCR_RESET);
/* reset the phy */
return genphy_soft_reset(phydev);
}
编译后,串口打印如下:
/ # ifconfig eth1 192.168.0.123 up
[ 9.559735] fec_enet_open
[ 9.562395] netdev.name:eth0
[ 9.565285] netdev.ifindex:2
[ 9.568344] mii_bus.name:fec_enet_mii_bus
[ 9.573303] fec_restart
[ 9.576094] fec_enet_mii_probe
[ 9.579167] fec_enet_mii_probe dev_id:0
[ 9.583012] phy_connect_direct
[ 9.586115] phy_attach_direct
[ 9.589091] phy_attach_direct start
[ 9.592584] phy_sysfs_create_links
[ 9.596195] phy_init_hw
[ 9.609465] phy_device_reset
[ 9.612384] smsc_phy_reset
[ 9.615127] rv 1:0xffff
[ 9.617694] rv 2:0xffff
[ 9.620186] rv 3:0xffff
[ 9.622742] phy_poll_reset
[ 10.242662] SMSC LAN8710/LAN8720 2188000.ethernet-1:00: phy_poll_reset failed: -110
[ 10.250766] fec 2188000.ethernet eth0: Unable to connect to phy
可以看出,读取寄存器的值全部未0xffff。大概猜测是mdio出问题了,但是没有什么手段来证明。
4.使用正点原子给的内核和设备树文件
下载,串口打印如下:
root@ATK-IMX6U:~# ifconfig eth0 192.168.0.123 up
root@ATK-IMX6U:~# ping 192.168.0.106
PING 192.168.0.106 (192.168.0.106) 56(84) bytes of data.
64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=0.996 ms
^V^C
--- 192.168.0.106 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.996/0.996/0.996/0.000 ms
root@ATK-IMX6U:~# ifconfig eth0 192.168.0.123 down
root@ATK-IMX6U:~# [ 47.794601] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
ifconfig eth0 192.ifconfig eth0 192.168.0.123[ 54.903020] fec 2188000.ethernet eth1: Link is Up - 100Mbps/Full - flow control rx/tx
[ 54.911214] IPv6: ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready
ifconfig eth0 192.
root@ATK-IMX6U:~#
root@ATK-IMX6U:~# ifconfig eth1 192.168.0.124 up
root@ATK-IMX6U:~# ping 192.168.0.106
PING 192.168.0.106 (192.168.0.106) 56(84) bytes of data.
64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=1.41 ms
64 bytes from 192.168.0.106: icmp_seq=2 ttl=64 time=0.918 ms
^C
--- 192.168.0.106 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.918/1.166/1.415/0.250 ms
root@ATK-IMX6U:~#
从上面可以看出,正点原子给内核和设备树,双网口是都可以正常使用的。到这里可以说明硬件肯定没问题,问题一定出在软件配置上,与想下载一个低版本且稳定的Linux版本,编译测试一下。
5.使用linux-5.19版本测试
使用低版本和稳定版本的Linux-5.19版本进行测试一下。下载源码,修改设备树和fec_probe函数,编译,下载。
下载,串口打印如下:
root@ATK-IMX6U:~# ifconfig eth0 192.168.0.123 up
root@ATK-IMX6U:~# ping 192.168.0.106
PING 192.168.0.106 (192.168.0.106) 56(84) bytes of data.
64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=3.95 ms
64 bytes from 192.168.0.106: icmp_seq=2 ttl=64 time=1.61 ms
^[[A64 bytes from 192.168.0.106: icmp_seq=3 ttl=64 time=1.31 ms
[ 47.430219] icm20608: disagrees about version of symbol module_layout
--- 192.168.0.106 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 1.316/2.296/3.955/1.179 ms
^Croot@ATK-IMX6U:~# ifconfig eth0 192.168.0.123 down
root@ATK-IMX6U:~# [ 57.655875] fec 2188000.ethernet eth1: Link is Up - 100Mbps/Full - flow control rx/tx
[ 57.663991] IPv6: ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready
ifconfig eth0 192.ifconfig eth1 192.168.0.124 up
root@ATK-IMX6U:~# ping 192.168.0.106
PING 192.168.0.106 (192.168.0.106) 56(84) bytes of data.
64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=2.67 ms
64 bytes from 192.168.0.106: icmp_seq=2 ttl=64 time=1.33 ms
64 bytes from 192.168.0.106: icmp_seq=3 ttl=64 time=1.32 ms
^C
--- 192.168.0.106 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 1.327/1.779/2.677/0.634 ms
root@ATK-IMX6U:~#
从上面可以看出,linux-5.19版本编译出的内核和设备树,双网口是都可以正常使用的。
那么问题来了,就是linux-6.3.5版本内核编译出的内核和设备树,只能使用fec2网卡,fec1网卡是由问题。为啥呢?
通过对比Linux-6.3.5和Linux-5.19版本的drivers/net下的代码,发现存在很大差异,如下图使用Beyong Compare软件对比结果如下:
6.上NXP论坛查资料
在NXP论坛上找到几个关于IMX6ULL linux下fec1不能使用的问题。但是详细看完后,发现只有一个人的问题与我当前是一样,但看到最后也没有看到解决方案。
于是,就在后面回复楼主的一封邮件,询问一下,他最后有没有解决该问题。NXP论坛该问题链接:https://community.nxp.com/t5/i-MX-Processors/imx6ull-lan8720A/m-p/1296584,感兴趣的可以去看一看该论坛上的问题。
唉,该问题困扰了我一周时间,花费了一周的每天晚上来定位,但到最后还是没解决。该问题先暂时放一放,后面有时间再来看怎么解决!如果大家知道是什么原因,或者有解决办法,可以后台告诉我一下。大家一起学习,交流!有兴趣的朋友,欢迎进群讨论嵌入式相关技术知识。
今天的内容到此就完了,感谢大家的收看,如有不正之处,欢迎批评指正,下期再见!
关于更多嵌入式C语言、FreeRTOS、RT-Thread、Linux应用编程、linux驱动等相关知识,关注公众号【嵌入式Linux知识共享】,后续精彩内容及时收看了解。