在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 board_init_r(gd_t *id, ulong dest_addr)
- {
- ulong malloc_start;
- #if !defined(CONFIG_SYS_NO_FLASH)
- ulong flash_size;
- #endif
- gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
- bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
- monitor_flash_len = _end_ofs;
- /* Enable caches */
- enable_caches();
- debug("monitor flash len: %08lX\n", monitor_flash_len);
- board_init(); /* Setup chipselects */
- /*
- * TODO: printing of the clock inforamtion of the board is now
- * implemented as part of bdinfo command. Currently only support for
- * davinci SOC's is added. Remove this check once all the board
- * implement this.
- */
- #ifdef CONFIG_CLOCKS
- set_cpu_clk_info(); /* Setup clock information */
- #endif
- serial_initialize();
- myspi_init(); /*init bcm5396*/
- printf("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
- #ifdef CONFIG_LOGBUFFER
2、 net/Eth.c
在其中加入配置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启动就可以了。
-
- zynq-uboot> tftp 0x2a00000 devicetree.dtb
- Using zynq_gem device
- TFTP from server 192.168.0.101; our IP address is 192.168.0.99
- Filename 'devicetree.dtb'.
- Load address: 0x2a00000
- Loading: T #
- done
- Bytes transferred = 13222 (33a6 hex)
- zynq-uboot> tftp 0x2000000 uramdisk.image.gz
- Using zynq_gem device
- TFTP from server 192.168.0.101; our IP address is 192.168.0.99
- Filename 'uramdisk.image.gz'.
- Load address: 0x2000000
- Loading: #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- ####################################
- done
- Bytes transferred = 5289509 (50b625 hex)
- zynq-uboot> tftp 0x3000000 uImage
- Using zynq_gem device
- TFTP from server 192.168.0.101; our IP address is 192.168.0.99
- Filename 'uImage'.
- Load address: 0x3000000
- Loading: T #################################################################
- #################################################################
- #################################################################
- ##########################
- done
- Bytes transferred = 3230680 (314bd8 hex)
- zynq-uboot> bootm 0x3000000 0x2000000 0x2a00000
- ## Booting kernel from Legacy Image at 03000000 ...
- Image Name: Linux-4.0.0-dayun
- Image Type: ARM Linux Kernel Image (uncompressed)
- Data Size: 3230616 Bytes = 3.1 MiB
- Load Address: 00008000
- Entry Point: 00008000
- Verifying Checksum ... OK
- ## Loading init Ramdisk from Legacy Image at 02000000 ...
- Image Name:
- Image Type: ARM Linux RAMDisk Image (gzip compressed)
- Data Size: 5289445 Bytes = 5 MiB
- Load Address: 00800000
- Entry Point: 00800000
- Verifying Checksum ... OK
- ## Flattened Device Tree blob at 02a00000
- Booting using the fdt blob at 0x02a00000
- Loading Kernel Image ... OK
- OK
- Loading Ramdisk to 1faf4000, end 1ffff5e5 ... OK
- Loading Device Tree to 1faed000, end 1faf33a5 ... OK
- Starting kernel ...
- Uncompressing Linux... done, booting the kernel.
- Booting Linux on physical CPU 0x0
- Linux version 4.0.0-dayun (root@shenvpc) (gcc version 5.2.1 20151005 (Linaro GCC 5.2-2015.11-2) ) #1 SMP PREEMPT Fri Apr 7 02:03:21 Local time zone must be set--s
- CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
- CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
- .......