uboot中eth网口实现分析

一、uboot mii命令讲解

1.1 mii命令

命令文件路径common/cmd_mii.c

U_BOOT_CMD(
	mii,	5,	1,	do_mii,
	"MII utility commands",
	"device                     - list available devices\n"
	"mii device            - set current device\n"
	"mii info                 - display MII PHY info\n"
	"mii read            - read  MII PHY  register \n"
	"mii write     - write MII PHY  register \n"
	"mii dump            - pretty-print   (0-5 only)\n"
	"Addr and/or reg may be ranges, e.g. 2-7."
);

注意:在使用mii命令之前应该执行一次ping或者其他的会发生联网动作的命令(如tftp、dhcp)。
打印device

mii device
MII devices: 'mdio0'
Current device: 'mdio0'

打印网络芯片信息

mii info
PHY 0x00: OUI = 0x5043, Model = 0x1D, Rev = 0x01, 1000baseT, FDX
PHY 0x01: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x02: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x03: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x04: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x05: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x06: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x07: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x08: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x09: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0A: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0B: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0C: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0D: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0E: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x0F: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x10: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x11: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x12: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x13: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x14: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x15: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x16: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x17: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x18: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x19: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1A: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1B: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1C: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1D: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1E: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX
PHY 0x1F: OUI = 0x0000, Model = 0x00, Rev = 0x00,  10baseT, HDX

没加addr默认地址从0~1F全部打印,我单板mido0只挂了一个phy,addr为0,可以看到只有0地址有信息。
OUI为PHY制造商组织的唯一标识符,规格书的一致。

1.2 解析在使用mii命令之前应该执行一次发生联网动作的命令

原因是需要初始化gmac,mdio和devname,要不然就会出现如下的情况:

mii info
NULL device name!
NULL device name!
NULL device name!
NULL device name!

在uboot进入start_armboot()(位于arch/arm/lib/board.c)的时候会有一次初始化devname的过程,但并没有赋值。

start_armboot()	// arch/arm/lib/board.c
	eth_initialize(gd->bd);
		miiphy_init();// net/eth.c
				INIT_LIST_HEAD (&mii_devs);//common/miiphyutil.c
				current_mii = NULL;	//devname的值		

在使用mii info命令的时候会从current读取devname的值。

do_mii() //common/cmd_mii.c
	devname = miiphy_get_current_dev();
		char *miiphy_get_current_dev () //common/miiphyutil.c
		{
			if (current_mii)
				return current_mii->name;
			return NULL;
		}

可以看到start_armboot()并没有初始化devname,初始化是在发生联网动作的命令里面初始化的。通过添加打印信息可以知道devname实际是mdio控制器的名称。

devname = miiphy_get_current_dev();
printf("devname = %s\n", devname);
mii info
devname = mdio0
PHY 0x00: OUI = 0x5043, Model = 0x1D, Rev = 0x01, 1000baseT, FDX
...

1.3 mii read wite

mii的读写最终调用mdio去操作网络芯片,但查看mii读写代码只有这两个函数

read_ret = dev->read (devname, addr, reg, value);
write_ret = dev->write (devname, addr, reg, value);

而dev是mii_dev的结构体,并没有具体的读写函数

struct mii_dev {
	struct list_head link;
	char *name;
	int (*read) (char *devname, unsigned char addr, unsigned char reg, unsigned short *value);
	int (*write) (char *devname, unsigned char addr, unsigned char reg, unsigned short value);
};

通过在drivers/net/higmacv300/mdio.c添加打印信息可以知道,在每次使用mii读写时,都会调用这里具体的读写函数。

mii info
run mdio.c, higmac_mdio_read, 28
PHY 0x00: OUI = 0x5043, Model = 0x1D, Rev = 0x01, 1000baseT, FDX

二、网口初始化

通过上面可以知道,uboot初始化过程中并没有初始化网络芯片,而是需要用到网络的时候才去初始化。

2.1 eth_init

在uboot网络设备路径有两个higmacv300,higmac文件夹,Hi3519v101使用的是higmacv300。

drivers/net/higmacv300/higmac.c
	eth_init();
		parse_module_parameters(); //模块参数,phy_intf,phy0_addr...
		higmac_init();
			higmac_sys_init(); // GMAC 时钟初始化
			higmac_mdiobus_driver_init(); //mdio总线初始化
			miiphy_register(mdio_bus[0], higmac0_mdio_read,
					higmac0_mdio_write); //注册mdio总线,确定读写函数
				new_dev->read = read;
				new_dev->write = write;
				new_dev->name = (char *)(new_dev + 1);
				...
				if (!current_mii)
					current_mii = new_dev; //将注册的新设备赋值给current_mii ,也就是前面mii命令使用到的
			phy_detected(); //phy检测
			miiphy_reset(); //phy复位
			//以上初始化只会调用一次
			select_current_linked_phy(); //选择链接的phy
				higmac_net_adjust_link();
					phy_fixup();//根据phy_id 选择不同的配置,我单板的phy_id = 0x1410dd1,不在默认配置项里面,也能正常使用
								//#define PHY_ID_KSZ8051		0x00221550
								//#define PHY_ID_KSZ8081		0x00221560
								//#define PHY_ID_KSZ9031		0x00221620
					phy_detected();//phy检测
					miiphy_link();//phy link状态
						miiphy_read(devname, addr, PHY_BMSR, &reg);//通过读取PHY_BMSR = 0x01网口状态寄存器的第2位网口link状态,1 link up; 0 link down;
							/* Determine if a link is active */
							if ((reg & PHY_BMSR_LS) != 0) {
								return (1);
							} else {
								return (0);
							}
						miiphy_duplex();//Determine full/half duplex 确认全双工/半双工
						miiphy_speed();//Determine the ethernet speed (10/100/1000)
						//如下对GMAC状态与phy状态进行对比,要是状态不同,则会对GMAC进行调整
						if (ld->link_stat != stat) {
							if (stat & HIGMAC_LINKED) {
								port_mode = calculate_port_mode(speed_mode,
									higmac_board_info[ld->index].phy_intf,
									is_duplex_half);
					
								higmac_set_macif(ld, port_mode, speed_mode);
					
								if (is_duplex_half)
									higmac_writel(ld, 0x0, MAC_DUPLEX_HALF_CTRL);
								else
									higmac_writel(ld, 0x1, MAC_DUPLEX_HALF_CTRL);
					
							}
							ld->link_stat = stat;
						}
				link_on://打印网络信息
				higmac_net_set_mac_address();//设置GMAC address
		higmac_desc_enable();//使能gmac

你可能感兴趣的:(linux,uboot,网口)