系列文章目录
- Exynos4412 移植针对Samsung的Linux-6.1(一)下载、配置、编译Linux-6.1
- Exynos4412 移植针对Samsung的Linux-6.1(二)SD卡驱动——解决无法挂载SD卡的根文件系统
- Exynos4412 移植针对Samsung的Linux-6.1(三)SD卡驱动——解决mmc0: Timeout waiting for hardware interrupt.
- Exynos4412 移植针对Samsung的Linux-6.1(四)NandFlash卡驱动
- Exynos4412 移植针对Samsung的Linux-6.1(五)DM9000网卡驱动
- Exynos4412 移植针对Samsung的Linux-6.1(六)SROMC寄存器的数值不正确的问题
- Exynos4412 移植Linux-6.1(七)挂载Ramdisk文件系统,【已解决】Couldn’t find valid RAM disk image starting at 0
Exynos4412 移植针对Samsung的Linux-6.1(五)DM9000网卡驱动
前言
:Linux-6.1对DM9000网卡是支持的,但是设备树的写法与Linux-5.4的写法不同。
1、不成功的设备树写法
刚开始编写设备树的时候,内核启动时始终无法加载DM9000驱动。如果把eth的compatible改成“simple-bus”,就能够加载驱动,但是不一定是DM9000的驱动。以下是不成功的DM9000设备树写法:
memory-controller@12570000 {
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x04000000 0x20000 // Bank0
1 0 0x05000000 0x20000 // Bank1
2 0 0x06000000 0x20000 // Bank2
3 0 0x07000000 0x20000>; // Bank3
ethernet@1,0{
compatible = "davicom,dm9000";
reg = <1 0 0x2 1 4 0x2>;
interrupt-parent = <&gpx0>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
samsung,srom-page-mode;// normal(1data)page mode configuration
samsung,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
2、成功的设备树写法
后来看到有博文解释,当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 <dt-bindings/clock/exynos4.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "exynos-pinctrl.h"
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
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 // Bank0
1 0 0x05000000 0x20000 // Bank1
2 0 0x06000000 0x20000 // Bank2
3 0 0x07000000 0x20000>; // Bank3
pinctrl-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 configuration
samsung,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 configuration
samsung,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 = <EXYNOS_PIN_FUNC_2>;*/
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 = <EXYNOS_PIN_FUNC_2>;*/
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 = <EXYNOS_PIN_FUNC_2>;*/
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 = <EXYNOS_PIN_FUNC_2>;*/
samsung,pin-pud = <0>;
samsung,pin-drv = <3>;
};
};
&serial_0 {
status = "okay";
};
3、exynos-srom.c中的BUG
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启动过程中,就已经初始化了。