提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
[一、修改 fec_main.c 文件](#一、修改 fec_main.c 文件)
[二、配置 Linux 内核,使能 LAN8720 驱动](#二、配置 Linux 内核,使能 LAN8720 驱动)
[三、修改 smsc.c 文件](#三、修改 smsc.c 文件)
前言
上一期更新了一部分的网络驱动修改,这一期我们继续介绍剩余部分。
一、修改 fec_main.c 文件
要 在 I.MX6ULL 上使用 LAN8720A , 需 要 修 改 一 下 Linux 内 核 源 码 , 打 开
drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_probe,在 fec_probe 中加入如下代码:
3438 static int
3439 fec_probe(struct platform_device *pdev)
3440 {
3441 struct fec_enet_private *fep;
3442 struct fec_platform_data *pdata;
3443 struct net_device *ndev;
3444 int i, irq, ret = 0;
3445 struct resource *r;
3446 const struct of_device_id *of_id;
3447 static int dev_id;
3448 struct device_node *np = pdev->dev.of_node, *phy_node;
3449 int num_tx_qs;
3450 int num_rx_qs;
3451
3452 /* 设置MX6UL_PAD_ENET1_TX_CLK和MX6UL_PAD_ENET2_TX_CLK
3453 * 这两个IO的复用寄存器的SION位为1。
3454 */
3455 void __iomem *IMX6U_ENET1_TX_CLK;
3456 void __iomem *IMX6U_ENET2_TX_CLK;
3457
3458 IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
3459 writel(0X14, IMX6U_ENET1_TX_CLK);
3460
3461 IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
3462 writel(0X14, IMX6U_ENET2_TX_CLK);
3463
3464 ......
3456 return ret;
3657 }
第3455~3462就是新加入的代码,如果要在 I.MX6ULL 上使用 LAN8720A 就需要设置ENET1 和 ENET2 的 TX_CLK 引脚复位寄存器的 SION 位为 1。
二、配置 Linux 内核,使能 LAN8720 驱动
输入命令"make menuconfig",打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs
选中Device Drivers,按enter进入

选中Network device support,按enter进入

选中 PHY Device support and infrastructure,按enter进入

选中 Drivers for SMSC PHYs,按enter进入

三、修改 smsc.c 文件
之所以修改这个文件,是因为LAN8720A驱动此方面的文件有问题,容易出现NFS挂载失败。
首先需要找到 LAN8720A 的驱动文件,LAN8720A 的驱动文件是 drivers/net/phy/smsc.c,
在此文件中有个叫做 smsc_phy_reset 的函数,看名字都知道这是 SMSC PHY 的复位函数,因
此,LAN8720A 肯定也会使用到这个复位函数,修改此函数的内容,修改以后的 smsc_phy_reset
函数内容如下所示:
1 static int smsc_phy_reset(struct phy_device *phydev)
2 {
3 int err, phy_reset;
4 int msec = 1;
5 struct device_node *np;
6 int timeout = 5000;
7 if(phydev->addr == 0) /* FEC1 */ {
8 np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000");
9
10 if (np == NULL) {
11 return -EINVAL;
12 }
13 }
14
15 if(phydev->addr == 1) /* FEC2 */ {
16 np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
17
18 if (np == NULL) {
19 return -EINVAL;
20 }
21 }
22
23 err = of_property_read_u32(np, "phy-reset-duration", &msec);
24 /* A sane reset duration should not be longer than 1s */
25 if (!err && msec > 1000)
26 msec = 1;
27
28 phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
29 if (!gpio_is_valid(phy_reset))
30 return;
31
32 gpio_direction_output(phy_reset, 0);
33 gpio_set_value(phy_reset, 0);
34 msleep(msec);
35 gpio_set_value(phy_reset, 1);
36
37 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
38 if (rc < 0)
39 return rc;
40
41 /* If the SMSC PHY is in power down mode, then set it
42 * in all capable mode before using it.
43 */
44 if ((rc & MII_LAN83C185_MODE_MASK) ==
45 MII_LAN83C185_MODE_POWERDOWN) {
46
47 /* set "all capable" mode and reset the phy */
48 rc |= MII_LAN83C185_MODE_ALL;
49 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
50 }
51
52 phy_write(phydev, MII_BMCR, BMCR_RESET);
53 /* wait end of reset (max 500 ms) */
54 do {
55 udelay(10);
56 if (timeout-- == 0)
57 return -1;
58 rc = phy_read(phydev, MII_BMCR);
59 } while (rc & BMCR_RESET);
60
61 return 0;
62 }
第 7~13 行,获取 FEC1 网卡对应的设备节点。
第 15~21行,获取 FEC2 网卡对应的设备节点。
第 23 行,从设备树中获取"phy-reset-duration"属性信息,也就是复位时间。
第 28 行,从设备树中获取"phy-reset-gpios"属性信息,也就是复位 IO。
第 32~35 行,设置 PHY 的复位 IO,复位 LAN8720A。
最后我们还需要在 drivers/net/phy/smsc.c 文件中添加两个头文件,因为修改后的 smsc_phy_reset 函数用到了 gpio_direction_output 和 gpio_set_value 这两个函数,需要添加的头文件如下所示:
#include <linux/of_gpio.h>
#include <linux/io.h>
四、网络驱动测试
修改好设备树和 Linux 内核以后重新编译一下,得到新的 zImage 镜像文件和 imx6ull-alientek-emmc.dtb 设备树文件,使用网线将 I.MX6U-ALPHA 开发板的两个网口与路由器或者电
脑连接起来,最后使用新的文件启动 Linux 内核。启动以后使用"ifconfig"命令查看一下当前
活动的网卡有哪些,结果如图所示:

从上图中可以看出,当前没有活动的网卡。输入命令"ifconfig -a"来查看一下开发板中存在的所有网卡,结果如下图所示:

上图中 can0 和 can1 为 CAN 接口的网卡,eth0 和 eth1 才是网络接口的网卡,其中eth0 对应于 ENET2,eth1 对应于 ENET1。使用如下命令依次打开 eth0 和 eth1 这两个网卡:
ifconfig eth0 up
ifconfig eth1 up
再次输入"ifconfig"命令来查看一下当前活动的网卡,结果如下图所示:

可以看出,此时 eth0 和 eth1 两个网卡都已经打开,并且工作正常,但是这两个网卡都还没有 IP 地址,所以不能进行 ping 等操作。使用如下命令给两个网卡配置 IP 地址:
ifconfig eth0 192.168.1.251
ifconfig eth1 192.168.1.252
上述命令配置 eth0 和 eth1 这两个网卡的 IP 地址分别为 192.168.1.251 和 192.168.1.252,注意 IP 地址选择的合理性,一定要和自己的电脑处于同一个网段内(也就是前三段),并且没有被其他的设备占用!设置好以后,使用"ping"命令来 ping 一下自己的主机,如果能 ping 通那说明网络驱动修改成功!比如我的 Ubuntu 主机 IP 地址为 192.168.1.250,使用如下命令 ping 一下:
ping 192.168.1.250
可以看出,ping 成功,说明网络驱动修改成功了,我们在后面的构建根文件系统和 Linux 驱动开发中就可以使用网络调试代码。
总结
上一期更新了一部分的网络驱动修改,这一期介绍了剩余的部分。并进行了网络驱动的测试。
总结一下移植步骤:
①、在 Linux 内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。
②、编译出参考板子对应的 zImage 和.dtb 文件。
③、使用参考板子的 zImage 文件和.dtb 文件在我们所使用的板子上启动 Linux 内核,看能
否启动。
④、如果能启动的话就万事大吉,如果不能启动那就悲剧了,需要调试 Linux 内核。不过
一般都会参考半导体官方的开发板设计自己的硬件,所以大部分情况下都会启动起来。启动
Linux 内核用到的外设不多,一般就 DRAM(Uboot 都初始化好的)和串口。作为终端使用的串口
一般都会参考半导体厂商的 Demo 板。
⑤、修改相应的驱动,像 NAND Flash、EMMC、SD 卡等驱动官方的 Linux 内核都是已经
提供好了,基本不会出问题。重点是网络驱动,因为 Linux 驱动开发一般都要通过网络调试代
码,所以一定要确保网络驱动工作正常。如果是处理器内部 MAC+外部 PHY 这种网络方案的
话,一般网络驱动都很好处理,因为在 Linux 内核中是有外部 PHY 通用驱动的。只要设置好复
位引脚、PHY 地址信息基本上都可以驱动起来。
⑥、Linux 内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定 Linux
内核移植成功以后就要开始根文件系统的构建。