zynq u-boot网络配置

来源:互联网 发布:平价凉鞋推荐知乎 编辑:程序博客网 时间:2024/05/24 06:38

原文地址: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 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, &regs->laddr[i][LADDR_LOW]);              writel(0, &regs->laddr[i][LADDR_HIGH]);              /* Do not use MATCHx register */              writel(0, &regs->match[i]);          }                writel(macaddrlow, &regs->laddr[0][LADDR_LOW]);          writel(macaddrhigh, &regs->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, &regs->idr);                    /* Disable the receiver & transmitter */              writel(0, &regs->nwctrl);              writel(0, &regs->txsr);              writel(0, &regs->rxsr);              writel(0, &regs->phymntnc);                    /* Clear the Hash registers for the mac address              * pointed by AddressPtr              */              writel(0x0, &regs->hashl);              /* Write bits [63:32] in TOP */              writel(0x0, &regs->hashh);                    /* Clear all counters */              for (i = 0; i <= stat_size; i++)                  readl(&regs->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, &regs->rxqbase);                    /* Setup for DMA Configuration register */              writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);                    /* Setup for Network Control register, MDIO, Rx and Tx enable */              setbits_le32(&regs->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, &regs->nwcfg);          setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |                          ZYNQ_GEM_NWCTRL_TXEN_MASK);                 return 0;      }  

完成这三个地方配置后,重新编译u-boot,网络才算完成,可以通过tftp加载devicetree,uramdisk.image.gz,uImage,这样要比通过JTAG dow到内存中快很多,最后通过bootm启动就可以了。


原创粉丝点击