前言
:Linux-6.1对DM9000网卡是支持的,但是设备树的写法与Linux-5.4的写法不同。
刚开始编写设备树的时候,内核启动时始终无法加载DM9000驱动。如果把eth的compatible改成“simple-bus”,就能够加载驱动,但是不一定是DM9000的驱动。以下是不成功的DM9000设备树写法:
memory-controller@12570000 {#address-cells = <2>;#size-cells = <1>;ranges = <0 0 0x04000000 0x20000 // Bank01 0 0x05000000 0x20000 // Bank12 0 0x06000000 0x20000 // Bank23 0 0x07000000 0x20000>; // Bank3ethernet@1,0{compatible = "davicom,dm9000";reg = <1 0 0x2 1 4 0x2>;interrupt-parent = <&gpx0>; interrupts = <6 IRQ_TYPE_EDGE_RISING>; samsung,srom-page-mode;// normal(1data)page mode configurationsamsung,srom-timing = <9 12 1 5 1 1>; davicom,no-eeprom;mac-address = [00 0c 29 d3 fe 1d];}; };
DM9000A的中断请求INT信号,是高电平有效,不是
上升沿有效.
include/dt-bindings/interrupt-controller/irq.h定义了中断类型的宏定义
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1
#define IRQ_TYPE_EDGE_FALLING 2
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH 4
#define IRQ_TYPE_LEVEL_LOW 8
后来看到有博文解释,当device与driver相匹配时,最终会调用drivers/base/dd.c中的really_probe()函数。那么,可以在该函数中添加printk,或者定义宏DEBUG(内核源码include/printk.h文件定义了pr_debug),来跟踪打印显示有哪些device被注册。通过这个方法发现,以上设备树的写法,DM9000的驱动和设备没有匹配,压根就没有注册DM9000的驱动,所以更换成为以下设备树写法。内核启动时,就可以发现DM9000了。成功的设备树写法如下:
/dts-v1/;
#include "exynos4.dtsi"
#include "exynos4412.dtsi"
#include "exynos4412-pinctrl.dtsi"
#include
#include
#include
#include "exynos-pinctrl.h"
#include / {model = "CBT4412 board based on Exynos4412";compatible = "samsung,exynos4412";chosen {stdout-path = &serial_0;};aliases{serial0 = "/serial@13800000";serial1 = "/serial@13800020";console = "/serial@13800000";mmc1 = "/mmc@12530000";mmc2 = "/&mshc_0";};memctrl:memory-controller@12570000 {#address-cells = <2>;#size-cells = <1>;ranges = <0 0 0x04000000 0x20000 // Bank01 0 0x05000000 0x20000 // Bank12 0 0x06000000 0x20000 // Bank23 0 0x07000000 0x20000>; // Bank3pinctrl-0 = <&srom_ctrl1 &srom_ctrl2 &ebi_data1 &ebi_data2>;pinctrl-name = "default";eth@1,0{reg = <1 0 0x2 1 4 0x2>;samsung,srom-page-mode;// normal(1data)page mode configurationsamsung,srom-timing = <9 12 1 5 1 1>;davicom,no-eeprom;mac-address = [00 0c 29 d3 fe 1d];};};memory@40000000 {device_type = "memory";reg = <0x40000000 0x40000000>;};fixed-rate-clocks {xxti {compatible = "samsung,clock-xxti";clock-frequency = <0>;};xusbxti {compatible = "samsung,clock-xusbxti";clock-frequency = <24000000>;};};ethernet@50000000{compatible = "davicom,dm9000";reg = <0x5000000 0x02 0x5000004 0x2>;interrupt-parent = <&gpx0>;interrupts = <7 IRQ_TYPE_EDGE_RISING>;samsung,srom-page-mode;// normal(1data)page mode configurationsamsung,srom-timing = <9 12 1 5 1 1>;davicom,no-eeprom;mac-address = [00 0c 29 d3 fe 1d];pinctrl-0 = <&srom_ctrl1 &srom_ctrl2 &ebi_data1 &ebi_data2>;pinctrl-name = "default";};
};&gpy0 {srom_ctrl1:srom_ctrl1{samsung,pins = "gpy0-1","gpy0-4","gpy0-5";samsung,pin-function = <2>; /*samsung,pin-function = ;*/samsung,pin-pud = <0>;samsung,pin-drv = <3>;};
};&gpy1 {srom_ctrl2:srom_ctrl2{samsung,pins = "gpy1-0","gpy1-1","gpy1-2","gpy1-3";samsung,pin-function = <2>; /*samsung,pin-function = ;*/samsung,pin-pud = <0>;samsung,pin-drv = <3>;};
};&gpy5 {ebi_data1:ebi_data1{samsung,pins = "gpy5-0","gpy5-1","gpy5-2","gpy5-3","gpy5-4","gpy5-5","gpy5-6","gpy5-7";samsung,pin-function = <2>; /*samsung,pin-function = ;*/samsung,pin-pud = <0>;samsung,pin-drv = <3>;}; }; &gpy6 {ebi_data2:ebi_data2{samsung,pins = "gpy6-0","gpy6-1","gpy6-2","gpy6-3","gpy6-4","gpy6-5","gpy6-6","gpy6-7";samsung,pin-function = <2>; /*samsung,pin-function = ;*/samsung,pin-pud = <0>;samsung,pin-drv = <3>;};};&serial_0 {status = "okay";
};
drivers/memory/samsung/exynos-srom.c中的exynos_srom_probe()函数是有BUG的。该函数会给4个bank配置参数。这是通过include/linux/of.h中的宏for_each_child_of_node(parent, child)来实现。但是,这个宏在实际调用中报错,错误的原因是child的指针是NULL。
#define for_each_child_of_node(parent, child) \for (child = of_get_next_child(parent, NULL); child != NULL; \child = of_get_next_child(parent, child))
#define for_each_node_by_name(dn, name) \for (dn = of_find_node_by_name(NULL, name); dn; \dn = of_find_node_by_name(dn, name))
我采用的方法是把for_each_child_of_node(np, child)改成for_each_node_by_name(child,“eth”)。当然,这个方法具有局限性,如果name不是eth,那么就不正确了。如果您有更好的方法,请在留言区讨论留言。
另外,实际的应用中,并不需要exynos_srom_probe()函数来初始化SROMC的参数,因为u-boot启动过程中,就已经初始化了。
参考文献:
DM9000驱动解析_xiyu_1986的博客-CSDN博客