原文地址:http://blog.csdn.net/zhaoxinfan/article/details/69662074#comments
在zynq开发板zc706上,网络通路由下面三个设备组成:
其中zynq负责对phy进行配置,当zynq上的网络控制器以及phy完成正确配置时,能够看到RJ45上面的黄灯亮,此时表明链路已经通了。如果u-boot中已经设置了IP地址,通过网线就可以ping通电脑,此时会打印host alive这句话。
但是如果板子不是这样做的,比如是下面这种方式:
这里用到了BCM5396网络交换芯片,此时要保证网络链路通就需要对5396和两个PHY进行配置。幸运地是,PHY0由5396进行配置,当我们对5396进行正确配置后,PHY0也就配置完成了,PHY1的配置还是老样子。整个配置可以分为两步走,首先通过SPI总线配置5396,再配置PHY1,完成全部配置后,就能看到RJ45上面的黄灯亮起。
u-boot中需要修改的代码主要涉及三个地方
1、 arch/arm/lib/Board.c
其中board_init_r函数中需要在网络驱动配置前加入配置bcm5396的函数调用,这里我放在了串口驱动配置之后运行。
void myspi_init()
{
XSpiPs Spi;
int i32Option,status;
int i;
unsigned char workBuf[10];
workBuf[0]=0xf0;
workBuf[1]=0x1;
g_SpiConfig = &XSpiPs_ConfigTable[0];
//Initialize the SPI device.
Spi.IsBusy = 0;
Spi.Config.BaseAddress = g_SpiConfig->BaseAddress;
//Spi.StatusHandler = StubStatusHandler;
Spi.SendBufferPtr = NULL;
Spi.RecvBufferPtr = NULL;
Spi.RequestedBytes = 0;
Spi.RemainingBytes = 0;
Spi.IsReady = 0x11111111;
XSpiPs_WriteReg(Spi.Config.BaseAddress,0,0x00020000);
//Initialize the SPI device. end
i32Option = 0x1 | 0x2 | 0x4 | 0x10;
Spi_SetOptions(&Spi, i32Option);
XSpiPs_SetSlaveSelect(&Spi,1 );
XSpiPs_SetClkPrescaler(&Spi, 6 );
workBuf[0]=0xf0;
workBuf[1]=0x1;
workBuf[2]=0;
for(i=0x10;i<=0x1f;i++)
{
status = writeBCM5396(&Spi, i, 0x20, workBuf );
}
printf("*****************Read SPI Reg of 5396******************\r\n");
printf("---BMC Status Registers(PAGE 0x10-0x1F)---\n");
for(i=0x10;i<=0x1f;i++)
{
status = readBCM5396(&Spi, i, 0x28, workBuf );
printf("port=%d,offset=0x28,data=0x%x\n",(i-0x10),workBuf[2]);
printf("port=%d,offset=0x29,data=0x%x\n",(i-0x10),workBuf[3]);
}
printf("---BMC Status Registers(PAGE 0x10-0x1F)---\n\r");
for(i=0x10;i<=0x1f;i++)
{
status = readBCM5396(&Spi, i, 0x20, workBuf );
printf("port=%d,offset=0x20,data=0x%x\n\r",(i-0x10),workBuf[2]);
printf("port=%d,offset=0x21,data=0x%x\n\r",(i-0x10),workBuf[3]);
}
}
3、 drivers/net/Zynq_gem.c
这里的修改是可选项,主要是配置phy,我这里使用的是marvell的88E1111,u-boot中提供的配置方法不起效,于是进行了手动配置。加了phy_detect和negotiat函数
static void phy_negotiat(struct eth_device *dev)
{
struct zynq_gem_priv *priv = dev->priv;
u16 control;
u16 status;
u16 temp;
u16 timeout_counter=0;
printf("Start PHY autonegotiation.\n");
phywrite(dev,priv->phyaddr, 22, 2);
phyread(dev, priv->phyaddr, 21, &control);
control |= 0x0030;
phywrite(dev, priv->phyaddr, 21, control);
phywrite(dev, priv->phyaddr, 22, 0);
phyread(dev, priv->phyaddr, 4, &control);
control |= 0x0800;
control |= 0x0400;
control |= (0x0100 | 0x0080);
control |= (0x0040 | 0x0020);
phywrite(dev, priv->phyaddr, 4, control);
phyread(dev, priv->phyaddr, 9,&control);
control |= 0x0300;
phywrite(dev, priv->phyaddr, 9,control);
phywrite(dev, priv->phyaddr, 22, 0);
phyread(dev, priv->phyaddr, 16,&control);
control |= (7 << 12); /* max number of gigabit attempts */
control |= (1 << 11); /* enable downshift */
phywrite(dev, priv->phyaddr, 16,control);
phyread(dev, priv->phyaddr, 0, &control);
control |= 0x1000;
control |= 0x0200;
phywrite(dev, priv->phyaddr, 0, control);
phyread(dev, priv->phyaddr, 0, &control);
control |= 0x8000;
phywrite(dev, priv->phyaddr, 0, control);
while (1)
{
phyread(dev, priv->phyaddr, 0, &control);
if (control & 0x8000)
{
continue;
}
else
{
break;
}
}
phyread(dev, priv->phyaddr, 1, &status);
printf("Waiting for PHY to complete autonegotiation.\n");
while ( !(status & 0x0020) )
{
phyread(dev, priv->phyaddr,19, &temp);
// timeout_counter++;
// if (timeout_counter == 30)
// {
// printf("Auto negotiation error\n");
// return;
// }
phyread(dev, priv->phyaddr, 1, &status);
}
printf("autonegotiation complete.\n");
}
static void phy_detection(struct eth_device *dev)
{
int i;
u16 phyreg;
struct zynq_gem_priv *priv = dev->priv;
if (priv->phyaddr != -1) {
phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg);
printf("phy reg is %d\n",phyreg);
if ((phyreg != 0xFFFF) &&
((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
/* Found a valid PHY address */
printf("Default phy address %d is valid\n",
priv->phyaddr);
return;
} else {
printf("PHY address is not setup correctly %d\n",
priv->phyaddr);
priv->phyaddr = -1;
}
}
printf("detecting phy address\n");
if (priv->phyaddr == -1) {
/* detect the PHY address */
for (i = 31; i >= 0; i--) {
phyread(dev, i, PHY_DETECT_REG, &phyreg);
if ((phyreg != 0xFFFF) &&
((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
/* Found a valid PHY address */
priv->phyaddr = i;
printf("Found valid phy address, %d\n", i);
return;
}
}
}
priv->phyaddr = 0;
printf("No PHY detected. Assuming a PHY at address 0\r\n");
}
static int zynq_gem_setup_mac(struct eth_device *dev)
{
u32 i, macaddrlow, macaddrhigh;
struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
/* Set the MAC bits [31:0] in BOT */
macaddrlow = dev->enetaddr[0];
macaddrlow |= dev->enetaddr[1] << 8;
macaddrlow |= dev->enetaddr[2] << 16;
macaddrlow |= dev->enetaddr[3] << 24;
/* Set MAC bits [47:32] in TOP */
macaddrhigh = dev->enetaddr[4];
macaddrhigh |= dev->enetaddr[5] << 8;
for (i = 0; i < 4; i++) {
writel(0, ®s->laddr[i][LADDR_LOW]);
writel(0, ®s->laddr[i][LADDR_HIGH]);
/* Do not use MATCHx register */
writel(0, ®s->match[i]);
}
writel(macaddrlow, ®s->laddr[0][LADDR_LOW]);
writel(macaddrhigh, ®s->laddr[0][LADDR_HIGH]);
return 0;
}
static int zynq_gem_init(struct eth_device *dev, bd_t * bis)
{
u32 i;
u16 tmp;
unsigned long clk_rate = 0;
struct phy_device *phydev;
const u32 stat_size = (sizeof(struct zynq_gem_regs) -
offsetof(struct zynq_gem_regs, stat)) / 4;
struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
struct zynq_gem_priv *priv = dev->priv;
const u32 supported = SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
if (!priv->init) {
/* Disable all interrupts */
writel(0xFFFFFFFF, ®s->idr);
/* Disable the receiver & transmitter */
writel(0, ®s->nwctrl);
writel(0, ®s->txsr);
writel(0, ®s->rxsr);
writel(0, ®s->phymntnc);
/* Clear the Hash registers for the mac address
* pointed by AddressPtr
*/
writel(0x0, ®s->hashl);
/* Write bits [63:32] in TOP */
writel(0x0, ®s->hashh);
/* Clear all counters */
for (i = 0; i <= stat_size; i++)
readl(®s->stat[i]);
/* Setup RxBD space */
memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd));
for (i = 0; i < RX_BUF; i++) {
priv->rx_bd[i].status = 0xF0000000;
priv->rx_bd[i].addr =
((u32)(priv->rxbuffers) +
(i * PKTSIZE_ALIGN));
}
/* WRAP bit to last BD */
priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK;
/* Write RxBDs to IP */
writel((u32)priv->rx_bd, ®s->rxqbase);
/* Setup for DMA Configuration register */
writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr);
/* Setup for Network Control register, MDIO, Rx and Tx enable */
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
priv->init++;
}
printf("phy detection.\n");
phy_detection(dev);
phy_rst(dev);
phy_negotiat(dev);
printf("--------phyaddr : 0x%x----\r\n", priv->phyaddr);
unsigned short PhyReg;
//change to page 0
phyread(dev, priv->phyaddr, 22, &PhyReg);
PhyReg = PhyReg & 0xfffe;
phywrite(dev, priv->phyaddr, 22, PhyReg);
phyread(dev, priv->phyaddr, 20, &PhyReg);
PhyReg = PhyReg | 0x82;
phywrite(dev, priv->phyaddr, 20, PhyReg);
/* reset phy */
phyread(dev, priv->phyaddr, 0, &PhyReg);
PhyReg |= 0x8000;
phywrite(dev, priv->phyaddr, 0, PhyReg);
puts("GEM link speed is 1000Mbps\n");
writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, ®s->nwcfg);
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
ZYNQ_GEM_NWCTRL_TXEN_MASK);
return 0;
}
完成这三个地方配置后,重新编译u-boot,网络才算完成,可以通过tftp加载devicetree,uramdisk.image.gz,uImage,这样要比通过JTAG dow到内存中快很多,最后通过bootm启动就可以了。