基于 88E1512 的 SGMII 接口千兆网驱动的应用经验
LSL
本设计是基于 DSP 的千兆网驱动,DSP 与 88E1512 通过 MDIO 接口进行配置,
千兆网数据通讯通过 DSP 与 88E1512 的 SGMII 接口连接。由于 88E1512 的资料比
较少,且网络上没有相应的驱动程序可以找到,因此在使用 88E1512 的 PHY 芯片
进行千兆网驱动程序的开发过程比较艰辛,通过个人的努力终于实现了千兆网的
功能。进行此次的应用经验分享,主要是为了减小需要开发 88E1512 驱动的难度。
其中 DSP 是基于 TI 的 TMS320C6678 进行驱动开发的。
首先,进行 88E1512 PHY 芯片的认识.
图 1 88E1510-1518 各型号的 PHY 芯片描述
我们即将讲解的 88E1512 芯片支持 RGMII 接口、SGMII 接口的千兆有线网或
千兆光纤的配置,由于 88E1512 芯片默认是基于 RGMII 的千兆有线网,如果在硬
件上使用 RGMII 的千兆有线网的朋友会发现,不需要对 PHY 芯片进行初始化,千
兆网也能够调通。但如果使用 SGMII 接口连接 PHY 芯片与 CPU 或 MCU 的,则需要
通过 MDIO 接口配置相应的寄存器。以下我们讲解的 SGMII 接口的驱动是基于
SGMII 的千兆有线网的配置,如果是基于光纤配置,软件不太一样,需要自己进
行重新配置。
图 2 RGMII 接口和 SGMII 接口的连接示意图(截图于数据手册)
驱动程序分为以下几个部分,分别是配置 Serdes 时钟、MDIO 寄存器配置、
SGMII 接口初始化、和 PHY 芯片 MDIO 接口重配置等三部分组成。
具体程序如下:
/**************************************************************************
****
*FUNCATION NAME : void app_PHY_88E1512Init(void)
*CREATE DATE : 2019-10-18
*CREATE BY : LSL
*FUNCTION : PHY芯片88E1512初始化(含时钟初始化/MDIO配置、SRGMIII配置)
***************************************************************************
***/
void app_PHY_88E1512Init(void)
{
configSerdes();
platform_write("Config serdes is OK!\n");
// Init_MDIO1();
PHY0_MDIO_Init(); //MDIO初始化
platform_write("PHY MDIO Config is OK!\n");
PHY0_SGMII_Init(); //SGMII初始化
platform_write("PHY SGMII Config is OK!\n");
PHY0_MDIO_Set();
}
/**************************************************************************
****
*FUNCATION NAME : void configSerdes(void)
*CREATE DATE : 2019-10-18
*CREATE BY : LSL
*FUNCTION : SGMII Serdes时钟配置 156.25-1.25GHz 倍频16
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
void configSerdes(void)
{
CSL_SGMII_STATUS sgmii_status;
/* Unlock the chip configuration registers to allow SGMII SERDES
registers to
* be written */
CSL_BootCfgUnlockKicker();
/* Configure the SERDES */
/* Multiply to be 8 with Quarter Rate in the Rx registers */
CSL_BootCfgSetSGMIIConfigPLL (0x00000081);
//31:25 Reserved 0000000
//23:24 LOOPBACK 00
// 22 ENOC 1
//21:18 EQ 0001
//17:15 CDR 001 -- first order threshold of 17
//14:12 LOS 000 -- tie off
//11:10 ALIGN 01 -- Comma Aligned
//09:07 TERM 100 -- tie off (100)
// 06 INVPAIR 0
//05:04 RATE 01 -- tie off (10) //00 = Full Rate, 01 = Half
Rate (*0.5), 10 = Quarter Rate (*0.25)
//03:01 BUSWIDTH 000 -- tie off
// 00 ENRX 1
// 0000 0000 0100 0100 0000 0010 0001 0001 = 0x0044_0211 -- My
estimated value
// 0000 0000 0100 0100 0000 0100 0001 0001 = 0x0044_0411 -- New DV
value
// 0000 0000 0000 1000 0000 1000 0100 0001 = 0x0008_0841 -- Original DV
value
platform_delaycycles(100);
// 0000 0000 0110 0000 1100 0110 0000 0001
CSL_BootCfgSetSGMIIRxConfig (0, 0x00700621);
//31:22 Reserved 0
//21:20 LOOPBACK 00
//19:18 RDTCT 00 -- tie off
// 17 ENIDL 0 -- tie off
// 16 MYSNC 1 -- tie off
//15:12 DEMPHASIS ???? - 0001 Lets give some de-emphasis
//11:08 SWING ????
// 07 CM 1 -- tie off
// 06 INVPAIR 0
//05:04 RATE 01 -- tie off
//03:01 BUSWIDTH 000 -- tie off
// 00 ENTX 1
// 0000 0000 0011 0001 ???? ???? 1001 0001 = 0x0031_1E91 -- My
estimated value
// 0000 0000 0000 0001 0000 1111 0001 0001 = 0x0001_0F11 -- New DV
value
// 0000 0000 0100 0000 0001 1110 0100 0001 = 0x0040_1e41 -- Original DV
value
CSL_BootCfgSetSGMIITxConfig (0, 0x000108A1);
/* Poll the SGMII0 lock bit to confirm that the sgmii module has
recognized
that the SERDES PLL has locked */
do
{
CSL_SGMII_getStatus(0, &sgmii_status);
// platform_delay(1000);
// platform_write("wait sgmii phy0 is lock\n");
} while (sgmii_status.bIsLocked != 1);
/* for(i=0;i<10000;i++)
{
}
*/
/* Poll the SGMII1 lock bit to confirm that the sgmii module has
recognized
that the SERDES PLL has locked */
timeout;
/**************************************************************************
****
*FUNCATION NAME : void PHY0_SGMII_Init (void)
*CREATE DATE : 2019-10-18
*CREATE BY : LSL
*FUNCTION : PH0 SGMII接口初始化
*MODIFY DATE :
*INPUT : 端口号,0和1
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
void PHY0_SGMII_Init (void)
{
CSL_SGMII_ADVABILITY sgmiiCfg;
CSL_SGMII_STATUS sgmiiStatus;
uint16_t
/* Reset the port before configuring it */
CSL_SGMII_doSoftReset (0);
while (CSL_SGMII_getSoftResetStatus (0) != 0);
/* Hold the port in soft reset and set up
* the SGMII control register:
* (1) Disable Master Mode
* (2) Enable Auto-negotiation
*/
CSL_SGMII_startRxTxSoftReset (0);
CSL_SGMII_disableLoopback(0);
CSL_SGMII_disableMasterMode (0);
CSL_SGMII_enableAutoNegotiation (0);
CSL_SGMII_endRxTxSoftReset (0);
/* Setup the Advertised Ability register for this port:
* (1) Enable Full duplex mode
* (2) Enable Auto Negotiation
* (3) Enable the Link
*/
sgmiiCfg.linkSpeed = CSL_SGMII_1000_MBPS;
sgmiiCfg.duplexMode = CSL_SGMII_FULL_DUPLEX;
// sgmiiCfg.bLinkUp = 1;//LSL 2019.10.08 添加
CSL_SGMII_setAdvAbility (0, &sgmiiCfg);
} while (sgmiiStatus.bIsLinkUp != 1);//2S超时则退出
CSL_SGMII_getStatus(0, &sgmiiStatus);
if (sgmiiStatus.bIsAutoNegError != 0)
return; /* This is an error condition */
CSL_SGMII_getStatus(0, &sgmiiStatus);
TSC_delay_ms(1);
timeout+=1; //超时计数
platform_write("*******wait PHY0 link*******\n");
// } while ((sgmiiStatus.bIsLinkUp !=
/* Wait for SGMII Autonegotiation to complete without error */
do
{
} while (sgmiiStatus.bIsAutoNegComplete != 1);
timeout=0;
do
{
//
1)&&(timeout<2000));//2S超时则退出
// platform_write("*******wait PHY0 Init is OK*******\n");
/* All done with configuration. Return Now. */
return;
}
/**************************************************************************
****
*FUNCATION NAME : Uint16 readPhyReg(uint8_t portnum,Uint32 phyaddr, Uint32
regaddr)
*CREATE DATE : 2019-12-27
*CREATE BY : LSL
*FUNCTION : 通过MDIO读取PHY的寄存器
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
Uint16 readPhyReg(uint8_t portnum,Uint32 phyaddr, Uint32 regaddr)
{
Phy Id 1
Uint16 value;
MDIOR->USER_GROUP[portnum].USER_ACCESS_REG = 0 // Read
| ( 1 << 31 ) // [31] Go
| ( 0 << 30 ) // [30] Read
while ( MDIOR->USER_GROUP[portnum].USER_ACCESS_REG & 0x80000000 ); //
value = MDIOR->USER_GROUP[portnum].USER_ACCESS_REG;
return value;
| ( 0 << 29 ) // [29] Ack
| (regaddr << 21 ) // [25-21] PHY register address
| (phyaddr << 16 ) // [20-16] PHY address
| ( 0 << 0 ) // [15-0] Data
;
Wait for Results
}
/**************************************************************************
****
*FUNCATION NAME : void writePhyReg(uint8_t portnum,Uint32 phyaddr, Uint32
regaddr, Uint16 data)
*CREATE DATE : 2019-12-27
*CREATE BY : LSL
*FUNCTION : 通过MDIO设置PHY的寄存器
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
void writePhyReg(uint8_t portnum,Uint32 phyaddr, Uint32 regaddr, Uint16
data)
{
Phy Id 1
address
Wait for Result
}
| ( 1 << 31 ) // [31] Go
| ( 1 << 30 ) // [30] Write
| ( 0 << 29 ) // [29] Ack
| (regaddr << 21 ) // [25-21] PHY register
| (phyaddr << 16 ) // [20-16] PHY address
| ( data << 0 ); // [15-0] Data
MDIOR->USER_GROUP[portnum].USER_ACCESS_REG = 0 // Read
while ( MDIOR->USER_GROUP[portnum].USER_ACCESS_REG & 0x80000000 ); //
writePhyReg(portnum,phyaddr, 22, pagenum);
/**************************************************************************
****
*FUNCATION NAME : void setPhyPage(uint8_t portnum,Uint32 phyaddr,Uint32
pagenum)
*CREATE DATE : 2019-12-27
*CREATE BY : LSL
*FUNCTION : 通过MDIO设置PHY的page号
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
void setPhyPage(uint8_t portnum,Uint32 phyaddr,Uint32 pagenum)
{
}
/**************************************************************************
****
*FUNCATION NAME : void PHY0_MDIO_Init(void)
*CREATE DATE : 2019-10-18
*CREATE BY : LSL
*FUNCTION : MDIO PHY0芯片初始化配置
*MODIFY DATE :
*INPUT : 端口号,0
*OUTPUT :
*RETURN :
*OTHERS :
***************************************************************************
***/
void PHY0_MDIO_Init(void)
{
Negotiation Process; Full-duplex
setPhyPage(0,APP_PORT_PHY0_ADDR,0);
writePhyReg(0,APP_PORT_PHY0_ADDR, 0, 0x700);//Isolate ;Restart Auto-
int regval;
// int page;
/*ctrl register config*/
/*link INT0 and INT1 setup*/
CSL_MDIO_enableLinkStatusChangeInterrupt(0, 0);