千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx

上传人:b****8 文档编号:22192698 上传时间:2023-02-03 格式:DOCX 页数:29 大小:96.18KB
下载 相关 举报
千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx_第1页
第1页 / 共29页
千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx_第2页
第2页 / 共29页
千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx_第3页
第3页 / 共29页
千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx_第4页
第4页 / 共29页
千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx

《千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx》由会员分享,可在线阅读,更多相关《千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx(29页珍藏版)》请在冰豆网上搜索。

千兆网口Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析Word格式.docx

如果CPU与PHY之间是RTBI接口,那么PCS层的工作在ETSEC中已经做完了,ETSEC中的TBI模块可以做PCS层的工作,PHY只需要做PMA和PMD的工作即可;

如果CPU与PHY之间是SGMII接口,那么PHY只需要完成PMD的工作,ETSEC中的PCS由TBI完成,而PMA由CPU自带的Serdes模块完成。

3BD表结构

在千兆以太网的驱动中,现在一般都使用一个叫BD表的东西来管理MAC层发送和接收的内存区域,如下图所示:

在IMMR映射的寄存器空间中有两组寄存器TBASEn和RBASEn,分别为TxBDRingn 

和 

RxBDRingn的指针。

MPC8314的ETSEC允许有8个TxBDRing和8个RxBDRing,他们都存放在内存的某个区域中。

每个BufferDescriptor 

都是有8个字节构成,两个字节的状态,两个字节的数据长度和四个字节的数据指针,这个指针指向内存的另一块地方,这才是真正存储发送接收数据的地方。

BufferDescriptor必须在网口初始化的时候初始化,并将自己的地址赋给TBASEn和RBASEn。

在网口驱动程序中可以看到,每个BDRing中的BD数量是可变的(我们设为64),而他们之间并没有指针连接,只是一段连续的空间,顺序下来的,所谓的环只是一个虚拟的概念,在最后一个BD时,需要将BD状态位中的W位(Wrap)置一,表示这是最后一个BD,他的下一个BD就是第一个BD。

如下图所示:

下面一节将结合uboot源码分析一下网口初始化以及PHY配置的过程,再下一节会分析内核中的驱动。

为什么先说uboot,因为在我看来,驱动程序就是分为两个部分,1 

按照Datasheet的说明去配置寄存器,2 

添加符合操作系统规范去融入操作系统。

在uboot下系统很简单,代码一目了然,所以我们应该在boot下先把寄存器配置好,再去分析复杂的多的内核代码。

这节分析uboot中的网口驱动代码。

网口驱动函数列表

函数名

函数用途

tsec_initialize()

网口初始化函数

tsec_init()

网口启动函数

tsec_local_mdio_write()

MDIO口写函数

tsec_local_mdio_read()

MDIO口读函数

tsec_send()

网口发送函数

tsec_recv()

网口接收函数

tsec_configure_serdes()

配置TBIPHY的函数

fsl_serdes_init()

Serdes模块初始化函数

init_phy()

PHY初始化函数

adjust_link()

根据PHY状态配置MAC的函数

2tsec_initialize()函数

该函数为ETSEC的初始化函数,在该函数中要初始化eth_device结构和私有的tsec_private结构,并初始化PHY。

inttsec_initialize(bd_t*bis,intindex,char*devname)

{

structeth_device*dev;

inti;

structtsec_private*priv;

/*为dev分配空间*/

dev=(structeth_device*)malloc(sizeof*dev);

if(NULL==dev) 

return0;

memset(dev,0,sizeof*dev);

/*为priv分配空间*/

priv=(structtsec_private*)malloc(sizeof(*priv));

if(NULL==priv) 

/*从tsec_info数组中取合适的值去初始化私有结构tsec_private*/

privlist[num_tsecs++]=priv;

priv->

regs=tsec_info[index].regs;

//每个tsec寄存器的基址

phyregs=tsec_info[index].miiregs;

//PHYMDIO读写状态寄存器基址

/*TBIPHY的MDIO读写状态寄存器基址*/

phyregs_sgmii=tsec_info[index].miiregs_sgmii;

phyaddr=tsec_info[index].phyaddr;

//PHY地址

flags=tsec_info[index].flags;

ID=index;

/*使用将priv结构体挂到dev结构体下,挂载tsec的打开、关闭、发送、接收函数*/

sprintf(dev->

name,tsec_info[index].devname);

dev->

iobase=0;

priv=priv;

init=tsec_init;

halt=tsec_halt;

send=tsec_send;

recv=tsec_recv;

/*初始化IP地址*/

for(i=0;

i<

6;

i++) 

enetaddr[i]=0;

/*设置当前活跃的网口名相当于setethacteTSECn,将多个网口级联*/

eth_register(dev);

/*通过设置MACCFG1寄存器重启MAC*/ 

regs->

maccfg1|=MACCFG1_SOFT_RESET;

udelay

(2);

/*SoftResetmustbeassertedfor3TXclocks*/ 

maccfg1&

=~(MACCFG1_SOFT_RESET);

/*挂载MII口的读写函数*/

#ifdefined(CONFIG_MII)||defined(CONFIG_CMD_MII)/ 

&

!

defined(BITBANGMII) 

miiphy_register(dev->

name,tsec_miiphy_read,tsec_miiphy_write);

#endif 

/*初始化PHY,并返回*/ 

returninit_phy(dev);

}

3init_phy()

staticintinit_phy(structeth_device*dev)

structtsec_private*priv=(structtsec_private*)dev->

priv;

structphy_info*curphy;

volatiletsec_t*regs=priv->

regs;

/*在TBIPA的寄存器中写入TBIPHY的地址*/ 

tbipa=CONFIG_SYS_TBIPA_VALUE+priv->

ID;

asm("

sync"

);

/*重启MII接口*/

phyregs->

miimcfg=MIIMCFG_RESET;

miimcfg=MIIMCFG_INIT_VALUE;

while(priv->

miimind&

MIIMIND_BUSY);

/*通过读PHY的2号3号寄存器获得该ETSEC外连的PHY的ID,搜索phy_info数组,找到符合ID的PHY信息返回。

*/ 

curphy=get_phy_info(dev);

if(curphy==NULL)

phyinfo=NULL;

printf("

%s:

NoPHYfound/n"

dev->

name);

/*如果是SGMII的接口,需要使用TBIPHY,初始化TBIPHY,注意这里名字竟然叫serdes配置,Linux里面也这么叫,真是误人子弟啊。

*/

if(regs->

ecntrl&

ECNTRL_SGMII_MODE) 

tsec_configure_serdes(priv);

/*在符合条件的PHY的phy_info数组中调用其初始化配置函数*/

phyinfo=curphy;

phy_run_commands(priv,priv->

phyinfo->

config);

return1;

4phy_info结构

Uboot中使用这个结构来完成phy的操作,所有的phy都要使用这个结构表示,下面是88E1111的phy_info结构:

structphy_infophy_info_M88E1111S={

0x01410cc, 

//PHYID

"

Marvell88E1111S"

 

//PHY名称

4, 

(structphy_cmd[])

/*配置数组,在调用priv->

config时将依次调用下面的内容,每个大括号内,第一个为PHY寄存器地址,第二个为value*/

/*ResetandconfigurethePHY*/ 

{MIIM_CONTROL,MIIM_CONTROL_RESET,NULL}, 

/*DelayRGMIITXandRX*/ 

{MIIM_GBIT_CONTROL,MIIM_GBIT_CONTROL_INIT,NULL}, 

{MIIM_ANAR,MIIM_ANAR_INIT,NULL}, 

{MIIM_CONTROL,MIIM_CONTROL_INIT,&

mii_cr_init},

{miim_end,}

}, 

/*启动数组,在ETSEC启动的时候要依次调用。

/*Statusisreadoncetoclearoldlinkstate*/ 

{MIIM_STATUS,miim_read,NULL}, 

/*Auto-negotiate*/ 

{MIIM_STATUS,miim_read,&

mii_parse_sr}, 

/*Readthestatus*/ 

{MIIM_88E1011_PHY_STATUS,miim_read,&

mii_parse_88E1011_psr}, 

{miim_end,} 

/*shutdown*/ 

},

};

需要注意的是,这个数组时uboot的源码中提供的,但是由于PHY与MAC之间接口使用的不同,这个数组中的内容需要根据需要,参考相应PHY的datasheet作出一定的修改。

5tsec_init()

该函数不会在初始化的时候调用,它在每当你使用网口的时候被调用,使用网口,不管是ping,还是tftp。

inttsec_init(structeth_device*dev,bd_t*bd)

uinttempval;

chartmpbuf[MAC_ADDR_LEN];

/*初始化MACCFG2和ECNTRL两个寄存器,这两个寄存器非常重要,它们主要是用来是配置MAC对PHY的接口。

在这里先给个初始化的值,默认为GMII。

*/ 

tsec_halt(dev);

maccfg2=MACCFG2_INIT_SETTINGS;

ecntrl=ECNTRL_INIT_SETTINGS;

/*配置MAC地址。

MAC_ADDR_LEN;

i++)

tmpbuf[MAC_ADDR_LEN-1-i]=dev->

enetaddr[i];

tempval=(tmpbuf[0]<

<

24)|(tmpbuf[1]<

16)|(tmpbuf[2]<

8)|

tmpbuf[3];

macstnaddr1=tempval;

tempval=*((uint*)(tmpbuf+4));

macstnaddr2=tempval;

/*resettheindicestozero*/ 

rxIdx=0;

txIdx=0;

/*清除其它的寄存器*/ 

init_registers(regs);

/*启动tsec*/ 

startup_tsec(dev);

/*Ifthere'

snolink,fail*/ 

return(priv->

link?

0:

-1);

6startup_tsec()

staticvoidstartup_tsec(structeth_device*dev)

/*初始化BD表基址指针*/

tbase=(unsignedint)(&

rtx.txbd[txIdx]);

rbase=(unsignedint)(&

rtx.rxbd[rxIdx]);

/*初始化RXBD*/

PKTBUFSRX;

i++){

rtx.rxbd[i].status=(RXBD_EMPTY|RXBD_INTERRUPT);

rtx.rxbd[i].length=0;

rtx.rxbd[i].bufPtr=(uint)NetRxPackets[i];

rtx.rxbd[PKTBUFSRX-1].status|=RXBD_WRAP;

/*初始化TXBD*/

TX_BUF_CNT;

rtx.txbd[i].status=0;

rtx.txbd[i].length=0;

rtx.txbd[i].bufPtr=0;

rtx.txbd[TX_BUF_CNT-1].status|=TXBD_WRAP;

/*又要去找phy_info数组了,这次调用的是startup中的命令和函数*/

if(priv->

phyinfo)

startup);

/*根据PHY的Copper侧值配置MAC寄存器*/

adjust_link(dev);

/*使能MACCFG1中的发送接收使能*/

maccfg1|=(MACCFG1_RX_EN|MACCFG1_TX_EN);

/*让DMA知道可以准备搬运了这里的DMA是ETSEC内部的,并不是CPU中的DMA单元。

dmactrl|=DMACTRL_INIT_SETTINGS;

tstat=TSTAT_CLEAR_THALT;

dmactrl&

=~(DMACTRL_GRS|DMACTRL_GTS);

参照上面的phy_info数组的startup中的内容得知这里phy_run_commands(priv,priv->

st

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1