RTL8211FS在zynq下调试@TOC
RTL8211介绍
RTL8211是一个系列的phy芯片,从uboot的驱动中看出,共有4个子系列(RTL8211B , RTL8211E, RTL8211F, RTL8211DN),每个系列的寄存器都有一定的差异,在初始化中不能用通用的驱动。
RTL8211FS在zynq裸机下调试遇到的问题
之前自己调试过RTL8211E,使用默认的xsdk程序即可正常工作,使用xsdk方式调试RTL8211FS,最开始是初始化错误,读取手册发现,现有的驱动主要是适配RTL8211E系列,RTL8211FS检测连接状态的特殊状态寄存器和RTL8211E并不相同,在get_Realtek_phy_speed()中尾部进行了修改
XEmacPs_PhyRead(xemacpsp, phy_addr, 26, &status_speed);
if (status_speed & IEEE_STAT_LINK_STATUS) {
temp_speed = status_speed & 0x30;
xil_printf("autonegotiation temp_speed=%x \r\n", temp_speed);
if (temp_speed == 0x20)
return 1000;
else if(temp_speed == 0x10)
return 100;
else if(temp_speed == 0x0)
return 10;
else
return 0;
}
修改之后,初始化没有出现问题,插拔网线都能正常检测到,但是就是ping不通,找了一下没能找到原因,按以前的经验该调试延时寄存器,手册中没找到相关寄存器。
RTL8211FS在u-boot和Linux系统下测试
因为在裸机下调试没有成功,转向u-boot和linux,于是创建petaLinux工程,
然后导入硬件信息,对u-boot和linux驱动进行配置(默认是包含了realtek的phy驱动),编译完成后烧写到flash,发现uboot中网口正常工作,linux系统下网口也正常工作,此时又回到裸机下调试RTL8211FS.
RTL8211FS裸机驱动调试
经过u-boot和linux下的测试,phy芯片都能正常工作,于是就参考u-boot下rtl8211fs phy的驱动,将裸机下的操作流程按照u-boot下的步骤实现
static u32_t get_RTL8211F_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
u16_t control;
u16_t status,regval;
u16_t status_speed;
u32_t timeout_counter = 0;
u32_t temp_speed;
xil_printf("Start RTL8211F autonegotiation \r\n");
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, IEEE_CTRL_RESET_MASK);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1f, 0xd08);
//XEmacPs_PhyRead(XEmacPs_PhyRead, phy_addr, 0x11, &control);
control = 0x109; //u-boot 中:默认值或上0x100
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x11, control);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1f, 0xd04);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x10, 0x617f);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1f, 0);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
control |= IEEE_PAUSE_MASK;
control |= ADVERTISE_100;
control |= ADVERTISE_10;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
&control);
control |= ADVERTISE_1000;
control =0x200;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_RESET_MASK;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
while (1) {
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
if (control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
sleep(1);
timeout_counter++;
if (timeout_counter == 30) {
xil_printf("Auto negotiation error \r\n");
return XST_FAILURE;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
}
xil_printf("autonegotiation complete \r\n");
XEmacPs_PhyRead(xemacpsp, phy_addr, 26, &status_speed);
if (status_speed & IEEE_STAT_LINK_STATUS) {
temp_speed = status_speed & 0x30;
xil_printf("autonegotiation temp_speed=%x \r\n", temp_speed);
if (temp_speed == 0x20)
return 1000;
else if(temp_speed == 0x10)
return 100;
else if(temp_speed == 0x0)
return 10;
else
return 0;
}
return XST_FAILURE;
}
从上面的操作中可以看到一些寄存器在手册上根本没有,按照手册上的操作后,ping操作还是没能成功,后面搜索了一下rtl8211fs,通过前面大神趟过的坑,发现page 0xd08 reg 0x11需要写入一个0x109(uboot下默认写的是或上0x100),改了此寄存器就能正常ping通了。
在get_Realtek_phy_speed()函数中,最前面,加入如下一句话即可兼容原有驱动
XEmacPs_PhyRead(xemacpsp, phy_addr, 3, &control);
if(control ==0xc916){
return get_RTL8211F_phy_speed(xemacpsp ,phy_addr );
}
在此处发现有一位大佬是另外的一种修改方式,测试了效果非常好,以下是我稍加整理,能保持原有驱动兼容
static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
u16_t control;
u16_t status;
u16_t status_speed;
u32_t timeout_counter = 0;
u32_t temp_speed;
XEmacPs_PhyRead(xemacpsp, phy_addr, 3, &control);
if(control ==0xc916){
XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, &control);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0xD08);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x10, 0x5E);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x11, 0x100);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0xA42);
usleep(10);
}
xil_printf("Start PHY autonegotiation \r\n");
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
control |= IEEE_PAUSE_MASK;
control |= ADVERTISE_100;
control |= ADVERTISE_10;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
&control);
control |= ADVERTISE_1000;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_RESET_MASK;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
while (1) {
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
if (control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
sleep(1);
timeout_counter++;
if (timeout_counter == 30) {
xil_printf("Auto negotiation error \r\n");
return XST_FAILURE;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
}
xil_printf("autonegotiation complete \r\n");
XEmacPs_PhyRead(xemacpsp, phy_addr, 3, &control);
if(control ==0xc916){
XEmacPs_PhyRead(xemacpsp, phy_addr, 26, &status_speed);
if (status_speed & IEEE_STAT_LINK_STATUS) {
temp_speed = status_speed & 0x30;
xil_printf("autonegotiation temp_speed=%x \r\n", temp_speed);
if (temp_speed == 0x20)
return 1000;
else if(temp_speed == 0x10)
return 100;
else if(temp_speed == 0x0)
return 10;
else
return 0;
}
}
XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG,
&status_speed);
if (status_speed & 0x400) {
temp_speed = status_speed & IEEE_SPEED_MASK;
if (temp_speed == IEEE_SPEED_1000)
return 1000;
else if(temp_speed == IEEE_SPEED_100)
return 100;
else
return 10;
}
return XST_FAILURE;
}
以上两种修改方式差不多,在此感谢2位大佬的分享。