Linux学习第8天:Linux内核移植(四、修改网络驱动):拿来主义,站在巨人的肩上

发布时间:2023年12月18日

? ? ? ? NXP使用的网络芯片型号为KSZ8081,而我的开发板网络芯片型号为LA8720A.两者复位引脚不同。

? ? ? ? 其步骤将从以下几个方面加以说明:

? ? ? ? 一、修改LAN8720的复位以及网络时钟引脚驱动

? ? ? ? 二、修改fec1和fec2节点的pinctrl-0属性

? ? ? ? 三、修改LAN8720A的PHY地址

? ? ? ? 四、修改fec_main.c文件

? ? ? ? 五、配置Linux内核,使能LAN8720A驱动

? ? ? ? 六、修改smsc.c文件

? ? ? ? 七、驱动测试

一、修改LAN8720的复位以及网络时钟引脚驱动

? ? ? ?打开设备树文件imx6ull-alientek-emmc.dts,注释掉以下两行:

//MX6ULL_PAD_SNVS_TAMPER7_GPIO5_IO07 0x70a1
//MX6ULL_PAD_SNVS_TAMPER8_GPIO5_IO08 0x00000000

? ? ? ? 在该设备树中文件中,关于spi4的函数中也需要注释掉引脚相关内容,如下:

//pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
......
//cs-gpios = <&gpio5 7 0>;

? ? ? ? 在设备树文件中找到iomuxc_snvs的节点,在该节点下添加复位引脚信息,如下:

1 &iomuxc_snvs {
2 pinctrl-names = "default_snvs";
3 pinctrl-0 = <&pinctrl_hog_2>;
4 imx6ul-evk {
5
...... /*省略掉其他*/
43
44 /*enet1 reset zuozhongkai*/
45 pinctrl_enet1_reset: enet1resetgrp {
46 fsl,pins = <
47 /* used for enet1 reset */
48 MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
49 >;
50 };
51
52 /*enet2 reset zuozhongkai*/
53 pinctrl_enet2_reset: enet2resetgrp {
54 fsl,pins = <
55 /* used for enet2 reset */
56 MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
57 >;
58 };
59 };
60 };

?二、修改fec1和fec2节点的pinctrl-0属性

? ? 在设备树文件中找到pinctrl1_enet1和pinctrl2_enet2两个节点,并在文件中修改对应的网络时钟引脚设置并保存修改好的设备树文件,如下:

309 pinctrl_enet1: enet1grp {
310 fsl,pins = <
311 MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
312 MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
313 MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
314 MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
315 MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
316 MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
317 MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
318 MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009
319 >;
320 };
321
322 pinctrl_enet2: enet2grp {
323 fsl,pins = <
324 MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
325 MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
326 MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
327 MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
328 MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
329 MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
330 MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
331 MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
332 MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
333 MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b009
334 >;
335 };

? ? ? ? 找到fec1和fec2两个节点,修改其中的pinctrl-0属性值。修改完成以后,如下:

1 &fec1 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_enet1
4 &pinctrl_enet1_reset>;
5 phy-mode = "rmii";
......
9 status = "okay";
10 };
11
12 &fec2 {
13 pinctrl-names = "default";
14 pinctrl-0 = <&pinctrl_enet2
15 &pinctrl_enet2_reset>;
16 phy-mode = "rmii";
......
36 };

三、修改LAN8720A的PHY地址

????????ENET1的LAN8720A地址为0x0,ENET2的LAN8720A地址为0x1

? ? ? ? ENET1网络复位引脚使用IO为GPIO5_IO07,低电平有效,复位低电平信号持续时间为200ms.

? ? ? ? ENET2网络复位引脚使用IO为GPIO5_IO08,低电平有效,复位低电平信号持续时间为200ms.

? ? ? ? 修改完成以后,如下:

171 &fec1 {
172 pinctrl-names = "default";
173 pinctrl-0 = <&pinctrl_enet1>;
174 phy-mode = "rmii";
175 phy-handle = <&ethphy0>;
176 phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
177 phy-reset-duration = <200>;
178 status = "okay";
179 };
180
181 &fec2 {
182 pinctrl-names = "default";
183 pinctrl-0 = <&pinctrl_enet2>;
184 phy-mode = "rmii";
185 phy-handle = <&ethphy1>;
186 phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
187 phy-reset-duration = <200>;
188 status = "okay";
189
190 mdio {
191 #address-cells = <1>;
192 #size-cells = <0>;
193
194 ethphy0: ethernet-phy@0 {
195 compatible = "ethernet-phy-ieee802.3-c22";
196 smsc,disable-energy-detect;
197 reg = <0>;
198 };
199
200 ethphy1: ethernet-phy@1 {
201 compatible = "ethernet-phy-ieee802.3-c22";
202 smsc,disable-energy-detect;
203 reg = <1>;
204 };
205 };
206 };

四、修改fec_main.c文件

? ? ? ? 设置ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1,如下:

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);

? 五、配置Linux内核,使能LAN8720A驱动

? ? ? ? 打开图形界面配置界面,选择使能LAN8720A驱动,对应的路径如下:

? ? ? ? Devce Drivers

? ? ? ? ? ? ? ? Network device support

? ? ? ? ? ? ? ? ? ? ? ? PHY Device support and infrastructure

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Drivers for SMSC PHYs

六、修改smsc.c文件

? ? ? ? 需要在uboot中对LAN8720A进行一次软复位,就是要设置BMCR寄存器bit15为1,否则在网络调试测试NFS挂载文件系统时成功率很低。找到smsc_phy_reset的函数,修改成如下所示:

#include<linux/of_gpio.h>
#include<linux/io.h>

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 = 50000;
7 if(phydev->addr == 0) /* FEC1 */ {
8 np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@
02188000");
9 if(np == NULL) {
10 return -EINVAL;
11 }
12 }
13
14 if(phydev->addr == 1) /* FEC2 */ {
15 np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@
020b4000");
16 if(np == NULL) {
17 return -EINVAL;
18 }
19 }
20
21 err = of_property_read_u32(np, "phy-reset-duration", &msec);
22 /* A sane reset duration should not be longer than 1s */
23 if (!err && msec > 1000)
24 msec = 1;
25 phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
26 if (!gpio_is_valid(phy_reset))
27 return;
28
29 gpio_direction_output(phy_reset, 0);
30 gpio_set_value(phy_reset, 0);
31 msleep(msec);
32 gpio_set_value(phy_reset, 1);
33
34 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
35 if (rc < 0)
36 return rc;
37
38 /* If the SMSC PHY is in power down mode, then set it
39 * in all capable mode before using it.
40 */
41 if ((rc & MII_LAN83C185_MODE_MASK) ==
MII_LAN83C185_MODE_POWERDOWN) {
42
43 /* set "all capable" mode and reset the phy */
44 rc |= MII_LAN83C185_MODE_ALL;
45 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
46 }
47
48 phy_write(phydev, MII_BMCR, BMCR_RESET);
49 /* wait end of reset (max 500 ms) */
50
51 do {
52 udelay(10);
53 if (timeout-- == 0)
54 return -1;
55 rc = phy_read(phydev, MII_BMCR);
56 } while (rc & BMCR_RESET);
57 return 0;
58 }

七、驱动测试

? ? ? ? 修改好设备树和Linux内核以后重新编译一下,会得到新的zImage镜像文件和设备树文件,使用新的文件启动Linux内核。启动以后使用ifconfig-a命令查看下当前活动的网卡.

? ? ? ? 使用ifconfig eth0 up和ifconfig eth1 up依次打开这两个网卡。

? ? ? ? 使用ifconfig etho 192.168.1.251和ifconfig etho 192.168.1.252命令配置俩网卡的IP地址。

? ? ? ? 使用ping命令测试网络是否可行。


? ? ? ? 本文仅是内核移植中网络驱动的移植,而不是网络驱动程序的开发。网络驱动程序的原理及开发笔者将在后面的学习中给出。

? ? ? ? 文中所涉及的代码全是参考正点原子阿尔法开发板配套资料整理而成,仅供学习使用,不得用于商业用途,特此说明。

文章来源:https://blog.csdn.net/jiage987450/article/details/132730571
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。