i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、
【公众号】迅为电子
第七十三章内核添加网卡驱动
网络驱动是 linux 里面驱动三巨头之一,linux 下的网络功能非常强大,嵌入式 linux 中也常常用到网络功能。本章我们就来学习一下如何在内核配置网卡驱动。
73.1 有线网络设备简介
这里我们不讨论电脑上的有线网卡,主要来看嵌入式上的有线网络设备。在选型的时候我们看某一个CPU支持以太网。但是在外围电路中,有一个叫网卡的芯片。他们是什么关系呢?明明CPU已经支持以太网了,为什么还要在加一个网卡芯片呢。我们带着这个疑问来往下思考。
嵌入式上的有线网络设备我们要分成俩个部分来看,一部分是MAC控制器部分,一部分是PHY芯片部分。而我说某一个CPU支不支持网卡,说的是这个CPU有没有MAC控制器。MAC控制器属于OSI七层网络模型中的数据链路层,主要作用是传输可靠的网络数据。而底板上的网卡芯片属于第二部分,也就是phy芯片。PHY芯片位于OSI七层网络模型中的物理层,主要作用是将MAC控制器发来的数据通过物理介质传输出去,MAC控制器和PHY芯片共同组成了嵌入式上的有线网络设备。
73.2 有线网络硬件方案
正式由于嵌入式上的网络设备分成了俩个部分,所以在嵌入式上常见的网络硬件方案也就被分成了俩种,一种是CPU支持有线网络,也就是CPU带MAC控制器,一种是CPU不支持有线网络,也就是没有MAC控制。我们分部来看一下这俩种方案。
第一种方案:CPU带MAC控制器
CPU带MAC控制器,是不是第一部分MAC控制器部分就满足了,所以我们只需要在外接PHY芯片即可。IMX8mmini内部一共有一个MAC控制器,所以IMX8mmini处理器支持一个网口,我们在设置硬件的时候只需要将这个PHY芯片连接到CPU的MAC控制器管脚即可。
第二种方案:CPU不带MAC控制器
CPU如果不带MAC控制器,是不是这个CPU就不支持网络了。如果我要使用有线网络要怎么办呢,既然CPU里面没有MAC控制器,我们是不是可以找一个外置的MAC芯片呢,不过这种外置的MAC芯片基本都是MAC和PHY一体的。比如我们的4412开发板,三星的4412处理器内部并没有MAC控制器,而是搭载了一个DM9621芯片。DM921芯片内置了MAC控制器和PHY功能,并且提供了一个USB接口,4412处理器通过USB接口来操作DM9621。
优缺点比较:
<1>如果CPU自带MAC控制器,网络速度一般比较快,比如龙芯2K1000处理器是双千兆网,并且成本比较低。
<2>如果CPU没有MAC控制器,使用外置的MAC芯片比较灵活,可以任意扩展多路网口,但是成本比较高,并且速度不是很快,一般只有10M或者100M。
73.3 MAC与PHY连接方式
73.3.1 CPU带MAC控制器
前面我们说了,如果CPU自带MAC控制器,MAC控制器要和PHY芯片连接起来,MAC控制器与PHY芯片的通信方式主要有四种,分别是MII,RMII,GMII和RGMII。
i.MX8M Mini处理器支持RGMII接口,所以在选型的时候我们要选择支持RGMII的网口芯片。如下图所示
底板上的PHY芯片使用的为RGMII,同样也是支持RGMII接口,如下图所示:
所以通过RGMII接口将MAC控制器和PHY芯片连接起来,如下图所示:
73.3.2 CPU不带MAC控制器
如果CPU不带MAC控制器,我们要外接MAC芯片,我们需要将CPU与MAC芯片连接起来,这个通讯放置主要取决于MAC芯片的接口,比如4412开发板上使用的DM9621为USB接口。就要使用CPU的USB接口连接到DM9621,如下图所示:
73.3.3 RGMII接口介绍
RGMII全称为Reduced Gigabit Media Independant Interface,主要用来连接PHY和MAC控制器,RGMII一共有12根信号线,具体含义如下:
除了RGMII接口,还有GMII,SMII,MII,RMII等,关于这些接口基本上也都是大同小异,这里就不在过多介绍。
73.3.4 MDIO接口介绍
MDIO全称为Management Data Input/Output,是一种简单的串行接口,一条是时钟线,一条是数据线。主要用来配置和管理PHY芯片。如下图所示:
73.3.5 RJ45接口介绍
RJ45接口一端连接到PHY芯片上,一端连接到网线,如下图所示:
但是RJ45座子不能和PHY芯片直接连接,中间需要一个网络变压器,网络变压器的作用主要是用来隔离和滤波。但是有的同学可能就比较疑惑了,为什么我没有在开发板上看到变压器呢。因为现在很多的RJ45的座子上内部都集成了网络变压器,比如iMX8MM开发板上的HR911130C。所以这部分大家在选型的时候一定要注意,如果RJ45座子内部没有集成编译器,需要外接变压器。RJ45 座子上一般有两个灯,一个黄色(橙色),一个绿色,绿色亮的话表示网络连接正常,黄色闪烁的话说明当前正在进行网络通信。这两个灯由 PHY 芯片控制,PHY 芯片会有两个引脚来连接 RJ45 座上的这两个灯。内部 MAC+外部 PHY+RJ45 座(内置网络变压器)就组成了一个完整的嵌入式网络接口硬件
原理图如下:
73.3.6 硬件连接框图
为了更形象的给大家展示在嵌入式上得硬件连接方式,作者制作了一个简易的硬件连接框图。
第一种方案:CPU带MAC控制器。第二种方案:CPU不带MAC控制器,使用USB扩展网口
73.4修改设备树
本节我们就来简单分析一下 I.MX8MM的网络驱动源码。首先肯定是设备树,NXP的 I.MX系列SOC网络绑定文档为Documentation/devicetree/bindings/net/fsl-fec.txt,此绑定文档描述了 I.MX 系列 SOC 网络设备树节点的要求。
①、必要属性
compatible:这个肯定是必须的,一般是“fsl,<soc>-fec”,比如 I.MX8MM的compatible 属性就是"fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec"。
reg:SOC 网络外设寄存器地址范围。
interrupts:网络中断。
phy-mode:网络所使用的 PHY 接口模式,是 MII 还是 RMII。
②、可选属性
phy-reset-gpios:PHY 芯片的复位引脚。
phy-reset-duration:PHY 复位引脚复位持续时间,单位为毫秒。只有当设置了phy-resetgpios 属性此属性才会有效,如果不设置此属性的话 PHY 芯片复位引脚的复位持续时间默认为1 毫秒,数值不能大于 1000 毫秒,大于 1000 毫秒的话就会强制设置为 1 毫秒。
phy-supply:PHY 芯片的电源调节。
phy-handle:连接到此网络设备的 PHY 芯片句柄。
fsl,num-tx-queues:此属性指定发送队列的数量,如果不指定的话默认为 1。
fsl,num-rx-queues:此属性指定接收队列的数量,如果不指定的话默认为 2。
fsl,magic-packet:此属性不用设置具体的值,直接将此属性名字写到设备树里面即可,表
示支持硬件魔术帧唤醒。
fsl,wakeup_irq:此属性设置唤醒中断索引。
stop-mode:如果此属性存在的话表明 SOC 需要设置 GPR 位来请求停止模式。
③、可选子节点
mdio:可以设置名为“mdio”的子节点,此子节点用于指定网络外设所使用的 MDIO 总线,
主要做为 PHY 节点的容器,也就是在 mdio 子节点下指定 PHY 相关的属性信息,具体信息可以参考 PHY 的绑定文档 Documentation/devicetree/bindings/net/phy.txt。
PHY 节点相关属性内容如下:
interrupts:中断属性,可以不需要。
interrupt-parent:中断控制器句柄,可以不需要。
reg:PHY 芯片地址,必须的!
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 进制格式。
max-speed:PHY 支持的最高速度,比如 10、100 或 1000。
我们打开/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi文件,fec1节点如下所示:
fec1: ethernet@30be0000 {
compatible = "fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
reg = <0x0 0x30be0000 0x0 0x10000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_ENET1_ROOT>,
<&clk IMX8MM_CLK_ENET1_ROOT>,
<&clk IMX8MM_CLK_ENET_TIMER_DIV>,
<&clk IMX8MM_CLK_ENET_REF_DIV>,
<&clk IMX8MM_CLK_ENET_PHY_REF_DIV>;
clock-names = "ipg", "ahb", "ptp",
"enet_clk_ref", "enet_out";
assigned-clocks = <&clk IMX8MM_CLK_ENET_AXI_SRC>,
<&clk IMX8MM_CLK_ENET_TIMER_SRC>,
<&clk IMX8MM_CLK_ENET_REF_SRC>,
<&clk IMX8MM_CLK_ENET_TIMER_DIV>;
assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>,
<&clk IMX8MM_SYS_PLL2_100M>,
<&clk IMX8MM_SYS_PLL2_125M>;
assigned-clock-rates = <0>, <0>, <125000000>, <100000000>;
stop-mode = <&gpr 0x10 3>;
fsl,num-tx-queues=<3>;
fsl,num-rx-queues=<3>;
fsl,wakeup_irq = <2>;
status = "disabled";
};
但是目前网卡还不能使用,在/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts设备树文件下,已经存在了网卡的设备节点信息,如下所示;
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec1>;
phy-mode = "rgmii-id";
phy-handle = <ðphy0>;
fsl,magic-packet;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
at803x,led-act-blind-workaround;
at803x,eee-okay;
at803x,vddio-1p8v;
};
};
};
但是上述两个网卡信息不完善,需要添加一些内容,红色代码为添加的内容,添加了复位引脚信息,修改后如下所示:
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec1>;
phy-mode = "rgmii-id";
phy-handle = <ðphy0>;
fsl,magic-packet;
status = "okay";
reset-gpio = <&gpio2 10 GPIO_ACTIVE_LOW>;
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
at803x,led-act-blind-workaround;
at803x,eee-okay;
at803x,vddio-1p8v;
};
};
};
73.5添加pinctrl信息
打开/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts设备树文件,首先添加GPIO引脚信息,在开发板上有一个网卡芯片,所以会有网卡GPIO引脚信息,在&iomuxc节点下写下如下内容:
pinctrl_fec1: fec1grp {
fsl,pins = <
MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3
MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x3
MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f
MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f
MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f
MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f
MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91
MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91
MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91
MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91
MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f
MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91
MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91
MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f
MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x19
>;
};
上述代码中的pinctrl_fec1是网卡信息的pinctrl信息,其实在/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts设备树文件中已经存在了,在iomuxc节点下,然后我们需要添加的是网卡芯片的复位引脚信息。在iomuxc节点下,我们将原来的以下内容删除
MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x19
添加内容如下:
MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10 0x19
网卡芯片使用了GPIO2_IO10作为复位引脚。需要我们手动添加。
需要注意的是,引脚功能只能被申请注册一次,所以需要把设备树文件中关于这两个引脚的其他申请信息删除或者注释掉。在设备树文件中搜索这个引脚,发现在pinctrl_usdhc1_gpio节点中使用到了GPIO2_IO10,所以需要把这两条语句删除或者注释掉。如下图所示:
73.6修改fec_main.c文件
修改/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/drivers/net/ethernet/freescale/fec_main.c文件,添加如下代码:
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
int reset_gpio;
reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
if (gpio_is_valid(reset_gpio)) {
ret = devm_gpio_request_one(dev, reset_gpio, GPIOF_OUT_INIT_HIGH, "FEC reset");
if (ret) {
dev_err(dev, "unable to get reset gpio\n");
//return ret;
}
gpio_set_value_cansleep(reset_gpio, 0);
mdelay(10);
gpio_set_value_cansleep(reset_gpio, 1);
mdelay(10);
}
73.7修改core.c文件
修改/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/net/wireless/core.c文件,注释掉如下代码:
static atomic_t wiphy_counter = ATOMIC_INIT(0);
添加代码,如下图所示:
static atomic_t wiphy_counter = ATOMIC_INIT(0);
添加代码,如下图所示,红色是新增的内容
void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
{
struct cfg80211_internal_bss *scan, *tmp;
struct cfg80211_beacon_registration *reg, *treg;
rfkill_destroy(rdev->rfkill);
list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
list_del(®->list);
kfree(reg);
}
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
//add by apple
atomic_dec(&wiphy_counter);
kfree(rdev);
}
73.8 编译测试
重新编译linux源码,然后烧写镜像。当开发板启动完成后,可以使用ifconfig命令查看当前的网卡信息。如下图所示:
可以使用下面的命令打开eth0网卡:
ifconfig eth0 up
然后可以使用网线进行测试,看一下是否能够连接网络。如果网卡设备正常,插入网线会有如下信息打印:
输入以下命令,ping一下路由器的ip地址,如下图所示:
如果我们ping百度的网址,发现ping不通,需要修改dns地址,修改