命令文件路径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制造商组织的唯一标识符,规格书的一致。
原因是需要初始化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
...
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初始化过程中并没有初始化网络芯片,而是需要用到网络的时候才去初始化。
在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, ®);//通过读取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