系统版本:Ubuntu18.04-64
编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)
uboot版本:2018.07 -linux4sam_6.0
板子型号:at91sama5d3x-xplained
MCU型号:sama5d36
内核中调试驱动,和uboot中会有些区别,因为内核启动过程是顺序启动的,硬件上电后,外部的器件要快速做好准备工作,内核代码初始化到这个器件如果器件没有完成上电复位,很可能会驱动失败,需要硬件和软件时序同步,这是非常重要的一点。
【Datasheet】PHY KSZ9031千兆网络芯片解读
[Linux 底层]U-boot ksz9031网络驱动调试
一、PHY在内核配置中需要使能对应的芯片厂商驱动Micrel公司PHY;
make menuconfig
Device Drivers --->
[*] Network device support --->
[*] Ethernet driver support --->
-*- MDIO bus device drivers ---- //MDIO控制器读取PHY寄存器
-*- PHY Device support and infrastructure --->
<*> Micrel PHYs //Micrel公司的ksz9031和ksz8081
二、修改设备树文件,硬件配置语言,所有的硬件相关信息都需要从设备树中获取。这是新内核的特性。
//arch/arm/boot/dts/at91-sama5d3_xplaint.dts
macb0: ethernet@f0028000 {
phy-mode = "rgmii";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
ethernet-phy@0 {
reg = <0x0>;
};
};
三、把编译出的zImage烧录进板子,查看打印信息
CAN device driver interface
at91_can f000c000.can: device registered (reg_base=(ptrval), irq=42)
libphy: MACB_mii_bus: probed
Generic PHY f0028000.ethernet-ffffffff:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:01, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 43 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
libphy: MACB_mii_bus: probed
Micrel KSZ8081 or KSZ8091 f802c000.ethernet-ffffffff:01: attached PHY driver [Micrel KSZ8081 or KSZ8091] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:01, irq=49)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 44 (36:d7:c3:e6:2a:c7)
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver5d36
其中,Generic PHY f0028000.ethernet-ffffffff:01;获取到得ID为全FF,硬件地址01;这里获取芯片的ID错误了,可能出错的点有MDIO配置错误,或者设备树配置错误;
不用太担心,可以根据打印的信息,查找对应的代码,添加上一些标识在里面;比如:macb f0028000.ethernet: macb_probe phy_interface=2.接口方式,可以搜索出对应的代码,然后添加Jack标识,再次烧录,即可打印出添加的信息;
linux-at91-linux-4.19-at91\drivers\net\ethernet\cadence\macb_main.c
static int macb_probe(struct platform_device *pdev)函数添加打印,
使用dev_info,用调试串口把信息打印出来,这是调试的必备手段;
图片
我们下面把PHY的接口方式,PHY ID都打印出来,看看和设备树是否能够对应上;
2、内核的网卡驱动找不到对应的PHY驱动
内核打印信息
macb f0028000.ethernet: Jack macb_probe phy_interface=2.
macb f0028000.ethernet: macb_mii_init name=f0028000.ethernet,id=ffffffff
libphy: MACB_mii_bus: probed
Generic PHY f0028000.ethernet-ffffffff:07: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:07, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 46 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
macb f802c000.ethernet: Jack macb_probe phy_interface=7.
macb f802c000.ethernet: macb_mii_init name=f802c000.ethernet,id=ffffffff
libphy: MACB_mii_bus: probed
Generic PHY f802c000.ethernet-ffffffff:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:01, irq=POLL)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 47 (06:50:95:f8:63:dc)
全是id=ffffffff,怀疑是MDIO有问题
这里只匹配了Ksz8081的驱动;
phy_interface = 2;代表是MII接口
图片
四、继续添加打印信息,PHY外部最多可挂载32个PHY设备,内核是如何做识别的呢,使用for循环扫描的,如果读取到ID不为全FF,则认为是有效的设备,会对该设备进行驱动配对;再往前添加一些打印信息,看看扫描的过程是如何的;
libphy: mdiobus_scan i= 0
libphy: get_phy_device addr=0,get_phy_id=-1,
libphy: mdiobus_scan i= 1
libphy: get_phy_device addr=1,get_phy_id=-1,
libphy: mdiobus_scan i= 2
libphy: get_phy_device addr=2,get_phy_id=-1,
libphy: mdiobus_scan i= 3
libphy: get_phy_device addr=3,get_phy_id=-1,
libphy: mdiobus_scan i= 4
libphy: get_phy_device addr=4,get_phy_id=-1,
libphy: mdiobus_scan i= 5
libphy: get_phy_device addr=5,get_phy_id=-1,
libphy: mdiobus_scan i= 6
libphy: get_phy_device addr=6,get_phy_id=-1,
libphy: mdiobus_scan i= 7
libphy: get_phy_device addr=7,get_phy_id=-1,
libphy: mdiobus_scan i= 8
libphy: get_phy_device addr=8,get_phy_id=-1,
libphy: mdiobus_scan i= 9
libphy: get_phy_device addr=9,get_phy_id=-1,
libphy: mdiobus_scan i= 10
libphy: get_phy_device addr=10,get_phy_id=-1,
libphy: mdiobus_scan i= 11
libphy: get_phy_device addr=11,get_phy_id=-1,
libphy: mdiobus_scan i= 12
libphy: get_phy_device addr=12,get_phy_id=-1,
libphy: mdiobus_scan i= 13
libphy: get_phy_device addr=13,get_phy_id=-1,
libphy: mdiobus_scan i= 14
libphy: get_phy_device addr=14,get_phy_id=-1,
libphy: mdiobus_scan i= 15
libphy: get_phy_device addr=15,get_phy_id=-1,
libphy: mdiobus_scan i= 16
libphy: get_phy_device addr=16,get_phy_id=-1,
libphy: mdiobus_scan i= 17
libphy: get_phy_device addr=17,get_phy_id=-1,
libphy: mdiobus_scan i= 18
libphy: get_phy_device addr=18,get_phy_id=-1,
libphy: mdiobus_scan i= 19
libphy: get_phy_device addr=19,get_phy_id=-1,
libphy: mdiobus_scan i= 20
libphy: get_phy_device addr=20,get_phy_id=-1,
libphy: mdiobus_scan i= 21
libphy: get_phy_device addr=21,get_phy_id=-1,
libphy: mdiobus_scan i= 22
libphy: get_phy_device addr=22,get_phy_id=-1,
libphy: mdiobus_scan i= 23
libphy: get_phy_device addr=23,get_phy_id=-1,
libphy: mdiobus_scan i= 24
libphy: get_phy_device addr=24,get_phy_id=-1,
libphy: mdiobus_scan i= 25
libphy: get_phy_device addr=25,get_phy_id=-1,
libphy: mdiobus_scan i= 26
libphy: get_phy_device addr=26,get_phy_id=-1,
libphy: mdiobus_scan i= 27
libphy: get_phy_device addr=27,get_phy_id=-1,
libphy: mdiobus_scan i= 28
libphy: get_phy_device addr=28,get_phy_id=-1,
libphy: mdiobus_scan i= 29
libphy: get_phy_device addr=29,get_phy_id=-1,
libphy: mdiobus_scan i= 30
libphy: get_phy_device addr=30,get_phy_id=-1,
libphy: mdiobus_scan i= 31
libphy: get_phy_device addr=31,get_phy_id=-1,
libphy: Fixed MDIO Bus: probed
CAN device driver interface
at91_can f000c000.can: device registered (reg_base=(ptrval), irq=45)
macb f0028000.ethernet: Jack macb_probe phy_interface=2.
macb f0028000.ethernet: Jack macb_is_gem gem_ethtool_ops
macb f0028000.ethernet: Jack macb_mdc_clk_div =0x100000
macb f0028000.ethernet: Jack macb_dbw =0x300000,bp->phy_interface=2
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=0,get_phy_id=25278624,
Generic PHY f0028000.ethernet-ffffffff:00: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:00, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 46 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
macb f802c000.ethernet: Jack macb_probe phy_interface=7.
macb f802c000.ethernet: Jack macb_is_gem macb_ethtool_ops
macb f802c000.ethernet: Jack macb_mdc_clk_div =0xc00
macb f802c000.ethernet: Jack macb_dbw =0xc00,bp->phy_interface=7
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=0,get_phy_id=2233697,
Micrel KSZ8081 or KSZ8091 f802c000.ethernet-ffffffff:00: attached PHY driver [Micrel KSZ8081 or KSZ8091] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:00, irq=POLL)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 44 (86:82:71:07:ba:d2)
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=0,get_phy_id=25278624;其中在地址0上面读取到了PHY的ID,转化为16进制:0xF113644,和手册上面无法对应;但是为什么就是驱动识别不了呢?
更改设备树的PHY芯片地址;
//arch/arm/boot/dts/at91-sama5d3_xplaint.dts
GMAC外部PHY的地址为7,dts中配置的地址为0,地址不匹配,读取不了数据;
macb0: ethernet@f0028000 {
phy-mode = "rgmii";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
ethernet-phy@0 {
reg = <0x0>;
};
};
改为:
macb0: ethernet@f0028000 {
phy-mode = "mii";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
ethernet-phy@7{
reg = <0x7>;
};
};
再次下载尝试,打印识别芯片正常,驱动可以正确匹配;
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=3,get_phy_id=-1,
mdio_bus f0028000.ethernet-ffffffff: MDIO device at address 3 is missing.
libphy: get_phy_device addr=0,get_phy_id=-1,
libphy: get_phy_device addr=1,get_phy_id=-1,
libphy: get_phy_device addr=2,get_phy_id=-1,
libphy: get_phy_device addr=3,get_phy_id=-1,
libphy: get_phy_device addr=4,get_phy_id=-1,
libphy: get_phy_device addr=5,get_phy_id=-1,
libphy: get_phy_device addr=6,get_phy_id=-1,
libphy: get_phy_device addr=7,get_phy_id=2233890,
libphy: get_phy_device addr=8,get_phy_id=-1,
libphy: get_phy_device addr=9,get_phy_id=-1,
libphy: get_phy_device addr=10,get_phy_id=-1,
libphy: get_phy_device addr=11,get_phy_id=-1,
libphy: get_phy_device addr=12,get_phy_id=-1,
libphy: get_phy_device addr=13,get_phy_id=-1,
libphy: get_phy_device addr=14,get_phy_id=-1,
libphy: get_phy_device addr=15,get_phy_id=-1,
libphy: get_phy_device addr=16,get_phy_id=-1,
libphy: get_phy_device addr=17,get_phy_id=-1,
libphy: get_phy_device addr=18,get_phy_id=-1,
libphy: get_phy_device addr=19,get_phy_id=-1,
libphy: get_phy_device addr=20,get_phy_id=-1,
libphy: get_phy_device addr=21,get_phy_id=-1,
libphy: get_phy_device addr=22,get_phy_id=-1,
libphy: get_phy_device addr=23,get_phy_id=-1,
libphy: get_phy_device addr=24,get_phy_id=-1,
libphy: get_phy_device addr=25,get_phy_id=-1,
libphy: get_phy_device addr=26,get_phy_id=-1,
libphy: get_phy_device addr=27,get_phy_id=-1,
libphy: get_phy_device addr=28,get_phy_id=-1,
libphy: get_phy_device addr=29,get_phy_id=-1,
libphy: get_phy_device addr=30,get_phy_id=-1,
libphy: get_phy_device addr=31,get_phy_id=-1,
Micrel KSZ9031 Gigabit PHY f0028000.ethernet-ffffffff:07: attached PHY driver [Micrel KSZ9031 Gigabit PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:07, irq=POLL)
五、下面梳理一下PHY的驱动加载流程
1、根据dts中的硬件配置,新建device
drivers\net\ethernet\cadence\macb_main.c
{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
{ .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },
static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
| MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_JUMBO,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
.jumbo_max_len = 10240,
};
static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,at32ap7000-macb" },
{ .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config },
{ .compatible = "cdns,macb" },
{ .compatible = "cdns,np4-macb", .data = &np4_config },
{ .compatible = "cdns,pc302-gem", .data = &pc302gem_config },
{ .compatible = "cdns,gem", .data = &pc302gem_config },
{ .compatible = "cdns,sam9x60-macb", .data = &at91sam9260_config },
{ .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config },
{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
{ .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },
{ .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
{ .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
{ .compatible = "cdns,emac", .data = &emac_config },
{ .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
{ .compatible = "cdns,zynq-gem", .data = &zynq_config },
{ /* sentinel */ }
};
2、device创建
macb_probe//入口函数
macb_mii_init//MII接口初始化
mdiobus_register//MDIO总线注册
device_register//设备注册
mdiobus_scan 0~32//循环扫描32个外部设备
get_phy_device//获取PHY ID
get_phy_id //获取硬件PHY的ID,用来匹配驱动
phy_device_create//PHY设备创建
phy_bus_match //匹配驱动函数
mdiobus_setup_mdiodev_from_board_info//MDIO创建设备
mdiobus_create_device//用于文件系统调试MDIO总线
macb_init//初始化完成
3、Driver创建
MODULE_DEVICE_TABLE(mdio, davicom_tbl);
module_phy_driver(dm91xx_driver);
启动文件系统尝试ping设备,验证驱动是否OK
测试结果为:ksz9031,需要多次插拔网线,才能检测到网线连接;
root@sama5d3-xplained:~# ifconfig
eth0 Link encap:Ethernet HWaddr ee:ab:c1:d2:e6:c6
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::ecab:c1ff:fed2:e6c6/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:1795 errors:0 dropped:0 overruns:0 frame:0
TX packets:1076 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:150514 (146.9 KiB) TX bytes:113046 (110.3 KiB)
Interrupt:46 Base address:0x8000
eth1 Link encap:Ethernet HWaddr aa:ab:c1:d2:e6:c6
inet addr:192.168.2.100 Bcast:192.168.2.255 Mask:255.255.255.0
inet6 addr: fe80::a8ab:c1ff:fed2:e6c6/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2334 errors:0 dropped:0 overruns:0 frame:0
TX packets:1797 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:696836 (680.5 KiB) TX bytes:671982 (656.2 KiB)
Interrupt:47 Base address:0xc000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:35 errors:0 dropped:0 overruns:0 frame:0
TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3836 (3.7 KiB) TX bytes:3836 (3.7 KiB)
怀疑是硬件和文件系统状态不同步导致;
4.1 ksz9031,使用外部杜邦线短接rst,使PHY芯片强制复位,看到网口灯正常;
4.2在文件系统中同步硬件状态;ifconfig eth0 down; ifconfig eth0 up; 强制让PHY驱动不工作后,再次使能;
4.3千兆网进入正常状态,多次试验,热插拔都可以正确识别,ping也可以正常通讯;
以上三个步骤做完,发现网卡驱动正常了;这就好 办了,说明我们的猜测是对的;
抱着芯片手册又啃了几遍,发现端倪;
通过代码走查,打印PHY寄存器状态值,MII_ADVERTISE(0x04)寄存器值为0xde1,为对称和不对称暂停功能;链路不能被激活;
//driver/net/phy/phy_device.c
//driver/net/phy/phy_device.c
/**
* genphy_restart_aneg - Enable and Restart Autonegotiation
* @phydev: target phy_device struct
*/
int genphy_restart_aneg(struct phy_device *phydev)
{
int ctl;//,ictl,adv,lpagb,iadv;
ctl = phy_read(phydev, MII_BMCR);
//pr_info("jack genphy_restart_aneg MII_BMCR = 0x%x\n",ctl);
/* Don't isolate the PHY if we're negotiating */
phy_write(phydev, MII_ADVERTISE, 0x1e1); //改为无暂停;让芯片正常侦测信号
ctl = 0;
ctl = phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
BMCR_ANENABLE | BMCR_ANRESTART);
//return phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
// BMCR_ANENABLE | BMCR_ANRESTART);
/*
pr_info("genphy_restart_aneg modify MII_BMCR = 0x%x\n",ctl);
//mdelay(3000);
ictl = phy_read(phydev, MII_BMSR);
pr_info("genphy_restart_aneg read MII_BMSR = 0x%x\n",ictl);
adv = phy_read(phydev, MII_CTRL1000);
pr_info("genphy_restart_aneg read MII_CTRL1000 = 0x%x\n",adv);
lpagb = phy_read(phydev, MII_STAT1000);
pr_info("genphy_restart_aneg read MII_STAT1000 = 0x%x\n",lpagb);
phy_write(phydev, MII_ADVERTISE, 0x1e1);
iadv = phy_read(phydev, MII_ADVERTISE);
pr_info("genphy_restart_aneg read MII_ADVERTISE = 0x%x\n",iadv);
*/
return ctl;
}
测试之后发现可以正常侦测网络,带载通讯也是正常的,网络驱动调试结束;
更多linux知识点推荐:
【C语言】数据结构链表算法福利视频
【C语言】C语言视频福利
[linux kernel] 内核启动流程梳理
[linux 底层]u-boot EMMC驱动
[linux 底层]u-boot图形化裁剪配置
[Linux 底层]U-boot ksz9031网络驱动调试
[Linux 底层]U-boot调试命令使用技巧
[Linux 底层]U-boot编译移植
[Linux 底层]U-boot烧录脚本介绍SecureCRT
[Linux 底层]bootstrap移植裁剪及编译
[Linux 底层] 平台软件分层介绍
[Linux 驱动] RS485测试程序编写
[Linux 驱动] CAN测试程序编写
推荐阅读:
芯片手册解读 | Linux底层