[Linux 底层]U-boot ksz8081网络驱动调试
2022-07-14 来源:csdn
micrel公司一款优秀的PHY芯片,关于芯片的介绍参考:
[Datasheet PHY] ksz8081数据手册解读
系统版本: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
与ksz9031很相似,公众部分可参考:
1、如何找到uboot官网开发板默认配置文件路径
2、如何进行公共信息配置
3、如何核对开发板硬件的参数
4、如何对uboot功能进行裁剪
5、设备树文件存放位置,及IO配置
6、网卡初始化流程,程序入口如何调用驱动文件接口;
[Linux 底层]U-boot ksz9031网络驱动调试
关注微信公众号,回复“ksz8081驱动”,免费下载ksz8081的驱动源代码。
硬件参考图如下:
1、设备树更改
phy-mode = “rmii”; PHY的接口方式为RMII 外部需要提供50MHZ时钟,或者通过内部倍频;
gpios,因为硬件设计上,把芯片的电源和RST单独控制,可给芯片复位,或者进行上下电操作;可在应用层进行调用;
macb1: ethernet@f802c000 {
phy-mode = 'rmii';
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&pinctrl_mcb1_rst >;
status = 'okay';
gpios = <
&pioC 18 GPIO_ACTIVE_HIGH ///poweren
&pioC 31 GPIO_ACTIVE_HIGH ///rst
>;
ethernet-phy@1 {
reg = <0x1>;
};
};
2、驱动初始化函数入口
#ifdef CONFIG_PHY_MICREL_KSZ8XXX
phy_micrel_ksz8xxx_init();
#endif
int phy_micrel_ksz8xxx_init(void)
{
printf('phy_micrel_ksz8xxx_init KSZ8081_drivern');
phy_register(&KSZ804_driver);
phy_register(&KSZ8031_driver);
phy_register(&KSZ8051_driver);
phy_register(&KSZ8081_driver);
phy_register(&KS8721_driver);
phy_register(&ksz8895_driver);
phy_register(&ksz886x_driver);
return 0;
}
50MHz晶振
static struct phy_driver KSZ8081_driver = {
.name = 'Micrel KSZ8081',
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
.config = &ksz_8081_config, //配置函数进行了重构,因为外部使用50M晶振,官网使用25M晶振
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
static int ksz_8081_config(struct phy_device *phydev)
{
int ret;
int regval;
//50M晶振配置
regval = phy_read(phydev, MDIO_DEVAD_NONE,MII_KSZPHY_CTRL);
regval |= KSZ8051_RMII_50MHZ_CLK;
phy_write(phydev, MDIO_DEVAD_NONE,MII_KSZPHY_CTRL, regval);
printf(' ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x%xn',regval);
ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
if (ret < 0)
return ret;
ret |= KSZPHY_OMSO_B_CAST_OFF;
//ret &= ~KSZPHY_OMSO_B_CAST_OFF;
printf(' ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x%xn',ret);
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
ret);
if (ret < 0)
return ret;
return genphy_config(phydev);
}
int genphy_config(struct phy_device *phydev)
{
int val;
u32 features;
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC);
/* Do we support autonegotiation? */
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
printf('genphy_config phyaddr=%d,MII_BMSR(%d)=0x%xn',phydev->addr,MII_BMSR,val);
if (val < 0)
return val;
if (val & BMSR_ANEGCAPABLE)
features |= SUPPORTED_Autoneg;
if (val & BMSR_100FULL)
features |= SUPPORTED_100baseT_Full;
if (val & BMSR_100HALF)
features |= SUPPORTED_100baseT_Half;
if (val & BMSR_10FULL)
features |= SUPPORTED_10baseT_Full;
if (val & BMSR_10HALF)
features |= SUPPORTED_10baseT_Half;
if (val & BMSR_ESTATEN) {
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
printf('genphy_config phyaddr=%d,MII_ESTATUS(%d)=0x%xn',phydev->addr,MII_ESTATUS,val);
if (val < 0)
return val;
if (val & ESTATUS_1000_TFULL)
features |= SUPPORTED_1000baseT_Full;
if (val & ESTATUS_1000_THALF)
features |= SUPPORTED_1000baseT_Half;
if (val & ESTATUS_1000_XFULL)
features |= SUPPORTED_1000baseX_Full;
if (val & ESTATUS_1000_XHALF)
features |= SUPPORTED_1000baseX_Half;
}
phydev->supported &= features;
phydev->advertising &= features;
genphy_config_aneg(phydev);
return 0;
}
/**
* genphy_config_aneg - restart auto-negotiation or write BMCR
* @phydev: target phy_device struct
*
* Description: If auto-negotiation is enabled, we configure the
* advertising, and then restart auto-negotiation. If it is not
* enabled, then we write the BMCR.
*/
int genphy_config_aneg(struct phy_device *phydev)
{
int result;
int ival = 0;
if (phydev->autoneg != AUTONEG_ENABLE)
return genphy_setup_forced(phydev);
#if 0
//set loopback
//Reg 0
ival |= (1 << 14 );
ival |= (1 << 6 );
ival &= ~(1 << 13 );
ival &= ~(1 << 12 );
ival |= (1 << 8 );
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ANENABLE & (~(1<<6)));
#endif
printf('genphy_config_aneg ival = 0x%x,test1111.n',ival);
result = genphy_config_advert(phydev);
if (result < 0) /* error */
{
return result;
}
printf('genphy_config_aneg result=%d test2222.n',result);
if (result == 0) {
/*
* Advertisment hasn't changed, but maybe aneg was never on to
* begin with? Or maybe phy was isolated?
*/
int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
printf('genphy_config_aneg MII_BMCR, ctl=0x%xn',ctl);
if (ctl < 0)
return ctl;
if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
result = 1; /* do restart aneg */
}
/*
* Only restart aneg if we are advertising something different
* than we were before.
*/
if (result > 0)
{
printf('genphy_config_aneg test3333.n');
result = genphy_restart_aneg(phydev);
}
return result;
}
3、编译之后,把u-boot.bin文件下载到板子,运行打印信息如下:
U-Boot 2018.07-linux4sam_6.0 (Oct 11 2020 - 23:57:20 -0700)
CPU: SAMA5D36
Crystal frequency: 12 MHz
CPU clock : 528 MHz
Master clock : 132 MHz
DRAM: 256 MiB
NAND: 256 MiB
MMC: Atmel mci: 0, Atmel mci: 1
Loading Environment from NAND... OK
In: serial@ffffee00
Out: serial@ffffee00
Err: serial@ffffee00
Netjack: macb_eth_probe phy-mode=mii,devname=ethernet@f0028000
eth0: ethernet@f0028000 [PRIME]macb_eth_probe phy-mode=rmii,devname=ethernet@f802c000
, eth1: ethernet@f802c000
Hit any key to stop autoboot: 0
=> pri
打印出phy-mode=rmii是从设备树里面读取的信息;
使用ping命令进行验证,是否能够正常通讯;
=> ping 192.168.2.108
CONFIG_DM_ETH _macb_init MACB_BIT(RMII) | MACB_BIT(CLKEN)
ethernet@f802c000: PHY present at 1,phy_id=0x22,macb->phy_addr=1
macb_phy_init name=ethernet@f802c000,phy_addr=1,ret=0
ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x8180
ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x202
ethernet@f802c000: Starting autonegotiation...
ethernet@f802c000: Autonegotiation complete
ethernet@f802c000: link up, 100Mbps full-duplex (lpa: 0xcde1)
macb_phy_init udelay(3000)
Using ethernet@f802c000 device
gmacb send
ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c
_macb_recv paddr=0x2fb6bec0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6bf40, length=64,phy_addr=1
_macb_recv paddr=0x2fb6bfc0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c040, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c0c0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c140, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c1c0, length=114,phy_addr=1
_macb_recv paddr=0x2fb6c240, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c2c0, length=64,phy_addr=1
gmacb send
ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c
_macb_recv paddr=0x2fb6c340, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c3c0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c4c0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c5c0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6c640, length=96,phy_addr=1
gmacb send
ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c
_macb_recv paddr=0x2fb6c740, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c7c0, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c840, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c8c0, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c940, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c9c0, length=96,phy_addr=1
_macb_recv paddr=0x2fb6cac0, length=64,phy_addr=1
gmacb send
ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c
_macb_recv paddr=0x2fb6cb40, length=96,phy_addr=1
_macb_recv paddr=0x2fb6cbc0, length=96,phy_addr=1
_macb_recv paddr=0x2fb6cc40, length=96,phy_addr=1
_macb_recv paddr=0x2fb6ccc0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6cd41, length=64,phy_addr=1
_macb_recv paddr=0x2fb6cdc3, length=64,phy_addr=1
_macb_recv paddr=0x2fb6be41, length=64,phy_addr=1
_macb_recv paddr=0x2fb6bec0, length=64,phy_addr=1
_macb_recv paddr=0x2fb6bf40, length=96,phy_addr=1
_macb_recv paddr=0x2fb6bfc0, length=96,phy_addr=1
_macb_recv paddr=0x2fb6c040, length=96,phy_addr=1
ARP Retry count exceeded; starting again
ping failed; host 192.168.2.108 is not alive
=>
根据以上信息可以看出,网络不通;驱动还是有问题;
=> ping 192.168.2.108
CONFIG_DM_ETH _macb_init MACB_BIT(RMII) | MACB_BIT(CLKEN)
//phy_id核对是正确的,地址是OK
ethernet@f802c000: PHY present at 1,phy_id=0x22,macb->phy_addr=1
//控制寄存器值正常;
macb_phy_init name=ethernet@f802c000,phy_addr=1,ret=0
ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x8180
ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x202
ethernet@f802c000: Starting autonegotiation...
ethernet@f802c000: Autonegotiation complete
ethernet@f802c000: link up, 100Mbps full-duplex (lpa: 0xcde1)
//自适应到网络连接,100M全双工
macb_phy_init udelay(3000)
//怀疑是MCU初始化的时序不同步,加了3000ms的延时,还是无效
Using ethernet@f802c000 device
4、后面想应该是初始化程序运行时,PHY芯片还没自检完成导致,因为芯片上电需要IO控制,需要加载起dts中的gpios的电源脚初始化芯片才能有电;
进行电源提前上电和RST提前拉成高电平尝试;
在初始化中添加GPIO的控制;
//PHY 9031的RESET脚使用CPU控制,PHY 8081的电源和RESET使用CPU控制
board/atmel/sama5d3_xplained/sama5d3_xplained.c
添加代码
static void sama5d3_xplained_phy_hw_init(void)
{
at91_set_pio_periph(AT91_PIO_PORTE, 9, 1); /* GPIO output up*/
at91_set_pio_periph(AT91_PIO_PORTC, 18, 1); /* GPIO output up*/
at91_set_pio_periph(AT91_PIO_PORTC, 31, 1); /* GPIO output up*/
at91_set_pio_periph(AT91_PIO_PORTB, 12, 1); /* LED GPIO output up*/
at91_set_pio_output(AT91_PIO_PORTE, 9, 1); //micrel ksz9031 reset gpio
at91_set_pio_output(AT91_PIO_PORTC, 18, 0); //micrel ksz8081 power gpio
at91_set_pio_output(AT91_PIO_PORTC, 31, 1); //micrel ksz8081 reset gpio
at91_set_pio_output(AT91_PIO_PORTB, 12, 0); //Board led on
}
int board_init(void)
{
/* adress of boot parameters */
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
#ifdef CONFIG_NAND_ATMEL
sama5d3_xplained_nand_hw_init();
#endif
#ifdef CONFIG_CMD_USB
sama5d3_xplained_usb_hw_init();
#endif
#ifdef CONFIG_GENERIC_ATMEL_MCI
sama5d3_xplained_mci0_hw_init();
#endif
// add by for xkk phy init gpio
sama5d3_xplained_phy_hw_init();
return 0;
}
编译之后烧录,验证网卡调通,使用ksz8081下载ftp程序如下:
U-Boot 2018.07-linux4sam_6.0 (Sep 29 2020 - 20:40:44 -0700)
CPU: SAMA5D36
Crystal frequency: 12 MHz
CPU clock : 528 MHz
Master clock : 132 MHz
DRAM: 256 MiB
NAND: 256 MiB
MMC: Atmel mci: 0, Atmel mci: 1
Loading Environment from NAND... OK
In: serial@ffffee00
Out: serial@ffffee00
Err: serial@ffffee00
Netjack: macb_eth_probe phy-mode=mii,devname=ethernet@f0028000
eth0: ethernet@f0028000macb_eth_probe phy-mode=rmii,devname=ethernet@f802c000
Error: ethernet@f802c000 address not set.
, eth-1: ethernet@f802c000
Hit any key to stop autoboot: 0
ethernet@f0028000: PHY present at 0
ethernet@f0028000: Starting autonegotiation...
ethernet@f0028000: Autonegotiation complete
ethernet@f0028000: link up, 100Mbps full-duplex (lpa: 0xcde1)
Using ethernet@f0028000 device
TFTP from server 192.168.1.108; our IP address is 192.168.1.100
Filename 'at91-sama5d3_xplained.dtb'.
Load address: 0x21000000
Loading: ####
375 KiB/s
done
Bytes transferred = 49969 (c331 hex)
ethernet@f0028000: PHY present at 0
ethernet@f0028000: Starting autonegotiation...
ethernet@f0028000: Autonegotiation complete
ethernet@f0028000: link up, 100Mbps full-duplex (lpa: 0xcde1)
Using ethernet@f0028000 device
TFTP from server 192.168.1.108; our IP address is 192.168.1.100
Filename 'zImage'.
Load address: 0x22000000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#######################
753.9 KiB/s
done
Bytes transferred = 4149536 (3f5120 hex)
## Flattened Device Tree blob at 21000000
Booting using the fdt blob at 0x21000000
Loading Device Tree to 2fb06000, end 2fb15330 ... OK
- 学习ARM开发(2)
- Linux帧缓冲设备驱动程序框架及图形界面GUI的移植
- Linux Kernel之flush_cache_all在ARM平台下是如何实现的
- 手把手教你写Linux设备驱动---中断(三)--workqueue实现(基于友善之臂4412开发板)
- makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解
- Ubuntu下安装arm-linux-gnueabi-xxx编译器
- 用Qemu运行/调试arm linux
- Linux内核异常处理体系结构详解(一)
- arm linux 移植 mtd-utils 1.x
- 基于gnu-arm-linux的LPC2220的简单工程模板