移植Linux内核到阿尔法开发板(三)修改网络驱动

1.修改设备树EMMC驱动

关闭EMMC 1.8V供电选项
在这里插入图片描述
  由上图可以看出,EMMC工作电压是3.3V,因此我们需要在usdhc2设备树节点中添加“no-1-8-v”选项,也就是关闭1.8V这个功能选项,防止内核在运行的时候使用1.8V去驱动EMMC,导致EMMC驱动出现问题,修改后的usdhc2节点内容如下:
在这里插入图片描述
修改后的代码如下所示:

/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include "imx6ull-alientek.dts"

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2_8bit>;
	pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
	bus-width = <8>;
	non-removable;
	no-1-8-v;
	status = "okay";
};

2.修改设备树网络驱动

    Linux驱动开发时经常使用网络调试驱动,因此需要将Linux系统网络驱动调试好,正点原子ALIENTEK-ALPHA开发板网络和NXP官方网络硬件上有所不同,NXP网络PHY芯片使用的 KSZ8081而ALIENTEK-ALPHA开发板网络PHY芯片使用的时LAN8720,两个网络芯片的复位IO口也不相同,因此NXP官方移植的Linux内核自带的网络驱动驱动ALIENTEK-ALPHA开发板上的网络存在问题,需要修改。

2.1NXP官方i.MX6ULL EVK开发板与ALIENTEK-ALPHA开发板网络接口对比

NXP官方i.MX6ULL EVK开发板ENET1网络PHY芯片引脚控制图
在这里插入图片描述
NXP官方i.MX6ULL EVK开发板ENET2网络PHY芯片引脚控制图
在这里插入图片描述
NXP官方i.MX6ULL EVK开发板ENET1和ENET2网络PHY芯片与MX6ULL芯片连接图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ALIENTEK-ALPHA开发板ENET1网络PHY芯片引脚控制图

在这里插入图片描述
ALIENTEK-ALPHA开发板ENET2网络PHY芯片引脚控制图
在这里插入图片描述
ALIENTEK-ALPHA开发板ENET1和ENET2网络PHY芯片与MX6ULL芯片连接图
在这里插入图片描述
在这里插入图片描述
NXP官方i.MX6ULL EVK开发板和ALIENTEK-ALPHA开发板ENET1和ENET2网络PHY芯片引脚连接对照表
在这里插入图片描述
  由上表可知NXP官方i.MX6ULL EVK开发板和ALIENTEK-ALPHA开发板ENET1和ENET2网络PHY芯片的复位引脚不同,其余引脚相同,NXP官方EVK开发板网络PHY芯片复位引脚是通过74LV595扩展而来,而ALIENTEK-ALPHA开发板网络PHY芯片复位引脚连接到I.M6ULL的SNVS_TAMPER7和SNVS_TAMPER8引脚。

2.2 修改LAN8720的复位及网络时钟引脚驱动

  修改NXP官方Linux内核网络驱动的设备树代码,打开设备树文件imx6ull-alientek.dts文件屏蔽74LV595控制引脚且增加ENET1和ENET2网路PHY芯片复位引脚控制,更改如下图所示:
在这里插入图片描述
在这里插入图片描述更改后的代码如下:

spi4 {  /****************** shield 74lv595 pin 20240303 **************/
		compatible = "spi-gpio";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_spi4>;
		/*pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;*/
		status = "okay";
		/*gpio-sck = <&gpio5 11 0>;
		gpio-mosi = <&gpio5 10 0>;
		cs-gpios = <&gpio5 7 0>;*/
		num-chipselects = <1>;
		#address-cells = <1>;
		#size-cells = <0>;

		gpio_spi: gpio_spi@0 {
			compatible = "fairchild,74hc595";
			gpio-controller;
			#gpio-cells = <2>;
			reg = <0>;
			registers-number = <1>;
			registers-default = /bits/ 8 <0x57>;
			spi-max-frequency = <100000>;
		};
	};
&iomuxc_snvs {
	pinctrl-names = "default_snvs";
        pinctrl-0 = <&pinctrl_hog_2>;
        imx6ul-evk {
		pinctrl_hog_2: hoggrp-2 {
                        fsl,pins = <
                                MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x80000000
                        >;
                };

		pinctrl_dvfs: dvfsgrp {
                        fsl,pins = <
                                MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03      0x79
                        >;
                };
		
		pinctrl_lcdif_reset: lcdifresetgrp {
                        fsl,pins = <
                                /* used for lcd reset */
                                MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
                        >;
                };

		pinctrl_spi4: spi4grp {
                        fsl,pins = <
						/**********shield 74lv595 pin **************************
                                MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10        0x70a1
                                MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11        0x70a1
                                MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07      0x70a1
                                MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x80000000
						*/
                        >;
                };

		/******************* add enet1 reset pin set 20240303 *********************/
		pinctrl_enet1_reset: enet1resetgrp {
                        fsl,pins = <
					            /********* enet1 reset pin set *****************/
                                MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07      0x10B0
                        >;
                };

		/******************* add enet2 reset pin set 20240303 *********************/
		pinctrl_enet2_reset: enet2resetgrp {
                        fsl,pins = <
					            /********* enet2 reset pin set *****************/
                                MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x10B0
                        >;
                };

        pinctrl_sai2_hp_det_b: sai2_hp_det_grp {
                        fsl,pins = <
                                MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04   0x17059
                        >;
                };
        };
};

2.3 修改ENET1和ENET2节点的pinctrl-0属性

  打开设备树imx6ull-alientek.dts文件中找到fec1fec2两个节点,修改其中的“pinctrl-0”属性值,增加ENET1和ENET2网络PHY芯片复位引脚初始化,修改后的代码如下所示:
在这里插入图片描述

2.4 设置LAN8720芯片复位引脚电平及地址

  设置ENET1和ENET2网络PHY芯片复位引脚电平及电平持续时间,复位有效信号为低电平且电平持续时间为200ms,修改后的代码如下图所示:
在这里插入图片描述
  由2.1章节可知,ALIENTEK-ALPHA开发板ENET1网络PHY芯片 LAN8720A的地址为0x0,ENET1网络PHY芯片 LAN8720A的地址为0x1,因此需要设置设备树文件PHY芯片的地址,打开设备树imx6ull-alientek.dts文件,找到fec2网络设备节点,fec2节点中mdio节点描述了ENET1和ENET2网络的PHY地址信息,“ethernet-phy@”后面的数字就是PHY的地址同时reg的值也表示PHY的地址,修改后的代码如下图所示:
在这里插入图片描述
修改后的fec1和fec2网络节点代码如下所示:

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1
	             &pinctrl_enet1_reset>;  /*enet1 reset pin set*/
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
	phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>; /*enet1 reset pin output low level*/
	phy-reset-duration = <200>;                   /*low level time 200ms*/
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2
	             &pinctrl_enet2_reset>;  /*enet2 reset pin set*/
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; /*enet2 reset pin output low level*/
	phy-reset-duration = <200>;                   /*low level time 200ms*/
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		/* set ENET1 PHY LAN8720 address 0x0*/
		ethphy0: ethernet-phy@0 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <0>;
		};
		
        /* set ENET2 PHY LAN8720 address 0x1*/
		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <1>;
		};
	};
};

保存修改后的文件,然后使用“make dtbs”命令重新编译下设备树文件,如下图所示:
在这里插入图片描述

2.5 修改fec_main.c文件

  在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;
    struct net_device *ndev;
    int i, irq, ret = 0;
    struct resource *r;
    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;

    /*set MX6UL_PAD_ENET1_TX_CLK and MX6UL_PAD_ENET2_TX_CLK 
      IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK register SION 
      IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK register SION */
      
    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);

fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);

    /* Init network device */
    ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
                  num_tx_qs, num_rx_qs);
    if (!ndev)
        return -ENOMEM;

SET_NETDEV_DEV(ndev, &pdev->dev);

    /* setup board info structure */
fep = netdev_priv(ndev);

    of_id = of_match_device(fec_dt_ids, &pdev->dev);
    if (of_id)
        pdev->id_entry = of_id->data;
fep->quirks = pdev->id_entry->driver_data;

    fep->netdev = ndev;
    fep->num_rx_queues = num_rx_qs;
fep->num_tx_queues = num_tx_qs;

#if !defined(CONFIG_M5272)
    /* default enable pause frame auto negotiation */
    if (fep->quirks & FEC_QUIRK_HAS_GBIT)
        fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
#endif

    /* Select default pin state */
pinctrl_pm_select_default_state(&pdev->dev);

    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    fep->hwp = devm_ioremap_resource(&pdev->dev, r);
    if (IS_ERR(fep->hwp)) {
        ret = PTR_ERR(fep->hwp);
        goto failed_ioremap;
}

    fep->pdev = pdev;
fep->dev_id = dev_id++;

platform_set_drvdata(pdev, ndev);

fec_enet_of_parse_stop_mode(pdev);

    if (of_get_property(np, "fsl,magic-packet", NULL))
        fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;

    phy_node = of_parse_phandle(np, "phy-handle", 0);
    if (!phy_node && of_phy_is_fixed_link(np)) {
        ret = of_phy_register_fixed_link(np);
        if (ret < 0) {
            dev_err(&pdev->dev,
                "broken fixed-link specification\n");
            goto failed_phy;
        }
        phy_node = of_node_get(np);
    }
fep->phy_node = phy_node;

    ret = of_get_phy_mode(pdev->dev.of_node);
    if (ret < 0) {
        pdata = dev_get_platdata(&pdev->dev);
        if (pdata)
            fep->phy_interface = pdata->phy;
        else
            fep->phy_interface = PHY_INTERFACE_MODE_MII;
    } else {
        fep->phy_interface = ret;
}

    fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
    if (IS_ERR(fep->clk_ipg)) {
        ret = PTR_ERR(fep->clk_ipg);
        goto failed_clk;
}

    fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
    if (IS_ERR(fep->clk_ahb)) {
        ret = PTR_ERR(fep->clk_ahb);
        goto failed_clk;
}

fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);

    /* enet_out is optional, depends on board */
    fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
    if (IS_ERR(fep->clk_enet_out))
        fep->clk_enet_out = NULL;

    fep->ptp_clk_on = false;
mutex_init(&fep->ptp_clk_mutex);

    /* clk_ref is optional, depends on board */
    fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
    if (IS_ERR(fep->clk_ref))
        fep->clk_ref = NULL;

    fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
    fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
    if (IS_ERR(fep->clk_ptp)) {
        fep->clk_ptp = NULL;
        fep->bufdesc_ex = false;
}

    pm_runtime_enable(&pdev->dev);
    ret = fec_enet_clk_enable(ndev, true);
    if (ret)
        goto failed_clk;

    fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
    if (!IS_ERR(fep->reg_phy)) {
        ret = regulator_enable(fep->reg_phy);
        if (ret) {
            dev_err(&pdev->dev,
                "Failed to enable phy regulator: %d\n", ret);
            goto failed_regulator;
        }
    } else {
        fep->reg_phy = NULL;
}

fec_reset_phy(pdev);

    if (fep->bufdesc_ex)
        fec_ptp_init(pdev);

    ret = fec_enet_init(ndev);
    if (ret)
        goto failed_init;

    for (i = 0; i < FEC_IRQ_NUM; i++) {
        irq = platform_get_irq(pdev, i);
        if (irq < 0) {
            if (i)
                break;
            ret = irq;
            goto failed_irq;
        }
        ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
                       0, pdev->name, ndev);
        if (ret)
            goto failed_irq;

        fep->irq[i] = irq;
}

    ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);
    if (!ret && irq < FEC_IRQ_NUM)
        fep->wake_irq = fep->irq[irq];
    else
        fep->wake_irq = fep->irq[0];

    init_completion(&fep->mdio_done);
    ret = fec_enet_mii_init(pdev);
    if (ret)
        goto failed_mii_init;

    /* Carrier starts down, phylib will bring it up */
    netif_carrier_off(ndev);
    fec_enet_clk_enable(ndev, false);
pinctrl_pm_select_sleep_state(&pdev->dev);

    ret = register_netdev(ndev);
    if (ret)
        goto failed_register;

    device_init_wakeup(&ndev->dev, fep->wol_flag &
               FEC_WOL_HAS_MAGIC_PACKET);

    if (fep->bufdesc_ex && fep->ptp_clock)
        netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);

    fep->rx_copybreak = COPYBREAK_DEFAULT;
    INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
return 0;

failed_register:
    fec_enet_mii_remove(fep);
failed_mii_init:
failed_irq:
failed_init:
    if (fep->reg_phy)
        regulator_disable(fep->reg_phy);
failed_regulator:
    fec_enet_clk_enable(ndev, false);
failed_clk:
failed_phy:
    of_node_put(phy_node);
failed_ioremap:
free_netdev(ndev);

    return ret;
}

2.6 配置Linux内核,使能LAN8720驱动

输入命令“make menuconfig”,打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:
-> Device Drivers
  -> Network device support
    -> PHY Device support and infrastructure
      -> Drivers for SMSC PHYs

配置过程如下图所示:

在这里插入图片描述
在这里插入图片描述
  上图中选择将“Drivers for SMSC PHYs”编译到Linux内核中,因此“<>”里面变成了“*”。LAN8720是SMSC公司产品,因此勾选这个就会编译LAN8720驱动,配置完成后点击保存配置按键后推出配置界面,重新编译Linux内核。

3.网络驱动测试

  将修改后的设备树和Linux内核重新编译,得到新的Linux镜像zImage文件和设备树imx6ull-alientek-emmc.dtb文件,将上面的两个文件拷贝到Ubuntu服务器tftpboot目录下,使用网线将ALIENTEK-ALPHA开发板ENET2网络接口使用网线连接到路由器,启动开发板uboot启动完成后自动从Ubuntu服务器tftpboot目录下下载Linux镜像文件和设备树文件,然后启动Linux内核,操作步骤如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用ifconfig -a命令查看ALIENTEK-ALPHA开发板中存在的所有网卡信息,结果如下图所示:
在这里插入图片描述
  由上图可知,ALIENTEK-ALPHA开发板存在两个网络接口eth0和eth1,其中
eth0对应于开发板上ENET2
网络,eth1对应于开发板ENET1网络,使用“ping”命令来ping下Ubuntu主机(IP地址为192.168.0.108)和百度,ping命令结果如下图所示:

在这里插入图片描述
在这里插入图片描述
将ALIENTEK-ALPHA开发板ENET2网线插入ENET1网络接口,使用ifconfig命令查看开发板网卡,如下图所示:
在这里插入图片描述
使用“ping”命令测试ALIENTEK-ALPHA开发板ENET1网络,测试结果如下图所示:
在这里插入图片描述
经过测试ALIENTEK-ALPHA开发板ENET1和ENET2网络工作正常,Linux内核网络驱动修改完成。

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值