最近生产了一批板卡,但是只焊接了EMAC1的网卡芯片,没有焊接EMAC0。这就无法直接使用了TI给的UBoot源码了。所以必须修改Uboot源码支持EMAC1.
首先先要弄明白EMAC工作原理。
管理EMAC的MII接口在初始化话的时候会读取网卡芯片的PHY地址,并保存在一个32位的寄存器中。比如我的PHY地址是3,那么这个寄存器的读取的值会成为0x00000008,即第三位置为1. 我们在源码中arch/arm/include/asm/arch-ti81xx/emac_defs.h 需要修改 EMAC_MDIO_PHY_NUM 为 3 . 源码中有这么一行:
#define EMAC_MDIO_PHY_MASK (1 << EMAC_MDIO_PHY_NUM)
所以MDIO的掩码是0x08。
我们需要使用EMAC1,就必须修改EMAC对应的基地址,所以相应的我们也在这个文件中添加:
//#define EMAC0
#ifdef EMAC0
#define EMAC_MDIO_PHY_NUM (1)
#define EMAC_BASE_ADDR (0x4A100000)
#define EMAC_WRAPPER_BASE_ADDR (0x4A100900)
#define EMAC_WRAPPER_RAM_ADDR (0x4A102000)
#else
#define EMAC_MDIO_PHY_NUM (3)
#define EMAC_WRAPPER_RAM_ADDR (0x4A122000)
#define EMAC_WRAPPER_BASE_ADDR (0x4A120900)
#define EMAC_BASE_ADDR (0x4A120000)
#endif
#define EMAC_MDIO_BASE_ADDR (0x4A100800)
#define DAVINCI_EMAC_VERSION2
#define DAVINCI_EMAC_GIG_ENABLE
#define EMAC_MDIO_BUS_FREQ (250000000UL)
#define EMAC_MDIO_CLOCK_FREQ (2000000UL)
之前我以为执行到这里,我的源码就修改完成了。结果我发现我从MDIO通信中的确识别了网卡,但是之后使用ping操作的时候,都不好使。找了好久终于发现了问题。
原来处理器默认使用EMAC0,所以初始化了EMAC0的相关IO。
但是EMAC1的IO没有初始化。打开drivers/net/davinci_emac.c
在函数davinci_emac_initialize() 的开始位置添加:
#ifndef EMAC0
#define EMAC1_PINCTRL_BASE *( volatile unsigned int* )( 0x481408C8 )
/*Initialize EMAC1 pins */
pReg = &EMAC1_PINCTRL_BASE;
for ( i = 0 ; i < 24 ; i++ )
{
debug_emac(“Before : 0x%08x\t”,readl(pReg));
writel(readl(pReg)|0x01,pReg);
debug_emac(“After : 0x%08x\n”,readl(pReg));
pReg++;
}
#endif
直到现在,已经完成了99%,也许好用,也许不好用。原因很特别:
看函数davinci_emac_initialize() 中的
for (i = 0; i < 256; i++) {
alive = readl(&adap_mdio->ALIVE);
// printf(“times:%03d,alive:0x%08x\n”,i,alive);
if (alive)
break;
udelay(10);
}
为什么要读这么多次?
可能是因为网卡没有初始完毕,CPU读得太快,所以需要重复读取。
当我使用双网卡的时候,我发现我的网卡地址分别是1和3. 所以我读取这个寄存器的时候,总会先返回了0x02然后再过一段时候之后再返回0x0a。所以这里需要自己做一些处理,需要一些延时或者重复读取的处理。