Zynq-Linux移植学习笔记之十-u-boot网络配置

本文详细介绍了在Zynq开发板zc706上进行u-boot网络配置的过程,包括配置BCM5396网络交换芯片、修改u-boot中涉及的代码,如`arch/arm/lib/Board.c`、`net/Eth.c`和`drivers/net/Zynq_gem.c`。完成这些步骤后,可以通过tftp加载文件并启动Linux内核。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考网址:http://blog.youkuaiyun.com/zhaoxinfan/article/details/69662074

在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的函数调用,这里我放在了串口驱动配置之后运行。

[cpp]  view plain  copy
  print ?
  1. void board_init_r(gd_t *id, ulong dest_addr)  
  2. {  
  3.     ulong malloc_start;  
  4. #if !defined(CONFIG_SYS_NO_FLASH)  
  5.     ulong flash_size;  
  6. #endif  
  7.   
  8.     gd->flags |= GD_FLG_RELOC;   /* tell others: relocation done */  
  9.     bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");  
  10.   
  11.     monitor_flash_len = _end_ofs;  
  12.   
  13.     /* Enable caches */  
  14.     enable_caches();  
  15.   
  16.     debug("monitor flash len: %08lX\n", monitor_flash_len);  
  17.     board_init();   /* Setup chipselects */  
  18.     /* 
  19.      * TODO: printing of the clock inforamtion of the board is now 
  20.      * implemented as part of bdinfo command. Currently only support for 
  21.      * davinci SOC's is added. Remove this check once all the board 
  22.      * implement this. 
  23.      */  
  24. #ifdef CONFIG_CLOCKS  
  25.     set_cpu_clk_info(); /* Setup clock information */  
  26. #endif  
  27.     serial_initialize();  
  28.   
  29.     myspi_init(); /*init bcm5396*/  
  30.   
  31.     printf("Now running in RAM - U-Boot at: %08lx\n", dest_addr);  
  32.   
  33. #ifdef CONFIG_LOGBUFFER  
 

2、  net/Eth.c

在其中加入配置bcm5396的代码

[cpp]  view plain  copy
  print ?
  1. void myspi_init()  
  2. {  
  3.     XSpiPs Spi;  
  4.     int i32Option,status;  
  5.     int i;  
  6.     unsigned char workBuf[10];  
  7.   
  8.     workBuf[0]=0xf0;  
  9.     workBuf[1]=0x1;  
  10.   
  11.     g_SpiConfig = &XSpiPs_ConfigTable[0];  
  12.   
  13.     //Initialize the SPI device.  
  14.     Spi.IsBusy = 0;  
  15.   
  16.     Spi.Config.BaseAddress = g_SpiConfig->BaseAddress;  
  17.     //Spi.StatusHandler = StubStatusHandler;  
  18.   
  19.     Spi.SendBufferPtr = NULL;  
  20.     Spi.RecvBufferPtr = NULL;  
  21.     Spi.RequestedBytes = 0;  
  22.     Spi.RemainingBytes = 0;  
  23.     Spi.IsReady = 0x11111111;  
  24.   
  25.     XSpiPs_WriteReg(Spi.Config.BaseAddress,0,0x00020000);  
  26.     //Initialize the SPI device. end  
  27.       
  28.     i32Option = 0x1 | 0x2 | 0x4 | 0x10;  
  29.     Spi_SetOptions(&Spi, i32Option);  
  30.   
  31.     XSpiPs_SetSlaveSelect(&Spi,1 );  
  32.   
  33.     XSpiPs_SetClkPrescaler(&Spi, 6 );  
  34.   
  35.     workBuf[0]=0xf0;  
  36.     workBuf[1]=0x1;  
  37.     workBuf[2]=0;  
  38.     for(i=0x10;i<=0x1f;i++)  
  39.     {  
  40.         status = writeBCM5396(&Spi, i, 0x20, workBuf );  
  41.     }  
  42.   
  43.     printf("*****************Read SPI Reg of 5396******************\r\n");  
  44.     printf("---BMC Status Registers(PAGE 0x10-0x1F)---\n");  
  45.     for(i=0x10;i<=0x1f;i++)  
  46.     {  
  47.           status = readBCM5396(&Spi, i, 0x28, workBuf );  
  48.           printf("port=%d,offset=0x28,data=0x%x\n",(i-0x10),workBuf[2]);  
  49.           printf("port=%d,offset=0x29,data=0x%x\n",(i-0x10),workBuf[3]);  
  50.         }  
  51.   
  52.     printf("---BMC Status Registers(PAGE 0x10-0x1F)---\n\r");  
  53.     for(i=0x10;i<=0x1f;i++)  
  54.     {  
  55.           status = readBCM5396(&Spi, i, 0x20, workBuf );  
  56.           printf("port=%d,offset=0x20,data=0x%x\n\r",(i-0x10),workBuf[2]);  
  57.       
  58.           printf("port=%d,offset=0x21,data=0x%x\n\r",(i-0x10),workBuf[3]);  
  59.         }  
  60.   
  61. }  
 

3、  drivers/net/Zynq_gem.c

这里的修改是可选项,主要是配置phy,我这里使用的是marvell的88E1111,u-boot中提供的配置方法不起效,于是进行了手动配置。加了phy_detect和negotiat函数

[cpp]  view plain  copy
  print ?
  1. static void phy_negotiat(struct eth_device *dev)  
  2. {  
  3.     struct zynq_gem_priv *priv = dev->priv;  
  4.     u16 control;  
  5.     u16 status;  
  6.     u16 temp;  
  7.     u16 timeout_counter=0;  
  8.       
  9.     printf("Start PHY autonegotiation.\n");  
  10.   
  11.     phywrite(dev,priv->phyaddr, 22, 2);  
  12.     phyread(dev, priv->phyaddr, 21, &control);  
  13.     control |= 0x0030;  
  14.     phywrite(dev, priv->phyaddr, 21, control);  
  15.   
  16.     phywrite(dev, priv->phyaddr, 22, 0);  
  17.   
  18.     phyread(dev, priv->phyaddr, 4, &control);  
  19.     control |= 0x0800;  
  20.     control |= 0x0400;  
  21.     control |= (0x0100 | 0x0080);  
  22.     control |= (0x0040 | 0x0020);  
  23.     phywrite(dev, priv->phyaddr, 4, control);  
  24.   
  25.     phyread(dev, priv->phyaddr, 9,&control);  
  26.     control |= 0x0300;  
  27.     phywrite(dev, priv->phyaddr, 9,control);  
  28.   
  29.     phywrite(dev, priv->phyaddr, 22, 0);  
  30.     phyread(dev, priv->phyaddr, 16,&control);  
  31.     control |= (7 << 12); /* max number of gigabit attempts */  
  32.     control |= (1 << 11); /* enable downshift */  
  33.     phywrite(dev, priv->phyaddr, 16,control);  
  34.     phyread(dev, priv->phyaddr, 0, &control);  
  35.     control |= 0x1000;  
  36.     control |= 0x0200;  
  37.     phywrite(dev, priv->phyaddr, 0, control);  
  38.   
  39.     phyread(dev, priv->phyaddr, 0, &control);  
  40.     control |= 0x8000;  
  41.     phywrite(dev, priv->phyaddr, 0, control);  
  42.   
  43.     while (1)   
  44.     {  
  45.         phyread(dev, priv->phyaddr, 0, &control);  
  46.         if (control & 0x8000)  
  47.         {  
  48.                 continue;  
  49.         }  
  50.         else  
  51.         {  
  52.                 break;  
  53.         }  
  54.     }  
  55.     phyread(dev, priv->phyaddr, 1, &status);  
  56.       
  57.     printf("Waiting for PHY to complete autonegotiation.\n");  
  58.   
  59.     while ( !(status & 0x0020) )   
  60.     {  
  61.         phyread(dev, priv->phyaddr,19,  &temp);  
  62. //      timeout_counter++;  
  63.   
  64. //      if (timeout_counter == 30)   
  65. //      {  
  66. //          printf("Auto negotiation error\n");  
  67. //          return;  
  68. //      }  
  69.         phyread(dev, priv->phyaddr, 1, &status);  
  70.     }  
  71.     printf("autonegotiation complete.\n");  
  72. }  
  73.   
  74. static void phy_detection(struct eth_device *dev)  
  75. {  
  76.     int i;  
  77.     u16 phyreg;  
  78.     struct zynq_gem_priv *priv = dev->priv;  
  79.   
  80.          
  81.     if (priv->phyaddr != -1) {  
  82.         phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg);  
  83.         printf("phy reg is %d\n",phyreg);  
  84.         if ((phyreg != 0xFFFF) &&  
  85.             ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {  
  86.             /* Found a valid PHY address */  
  87.             printf("Default phy address %d is valid\n",  
  88.                   priv->phyaddr);  
  89.             return;  
  90.         } else {  
  91.             printf("PHY address is not setup correctly %d\n",  
  92.                   priv->phyaddr);  
  93.             priv->phyaddr = -1;  
  94.         }  
  95.     }  
  96.     printf("detecting phy address\n");  
  97.     if (priv->phyaddr == -1) {  
  98.         /* detect the PHY address */  
  99.         for (i = 31; i >= 0; i--) {  
  100.             phyread(dev, i, PHY_DETECT_REG, &phyreg);  
  101.             if ((phyreg != 0xFFFF) &&  
  102.                 ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {  
  103.                 /* Found a valid PHY address */  
  104.                 priv->phyaddr = i;  
  105.                 printf("Found valid phy address, %d\n", i);  
  106.                 return;  
  107.             }  
  108.         }  
  109.     }  
  110.     priv->phyaddr = 0;  
  111.     printf("No PHY detected.  Assuming a PHY at address 0\r\n");      
  112. }  
  113.   
  114. static int zynq_gem_setup_mac(struct eth_device *dev)  
  115. {  
  116.     u32 i, macaddrlow, macaddrhigh;  
  117.     struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;  
  118.   
  119.     /* Set the MAC bits [31:0] in BOT */  
  120.     macaddrlow = dev->enetaddr[0];  
  121.     macaddrlow |= dev->enetaddr[1] << 8;  
  122.     macaddrlow |= dev->enetaddr[2] << 16;  
  123.     macaddrlow |= dev->enetaddr[3] << 24;  
  124.   
  125.     /* Set MAC bits [47:32] in TOP */  
  126.     macaddrhigh = dev->enetaddr[4];  
  127.     macaddrhigh |= dev->enetaddr[5] << 8;  
  128.   
  129.     for (i = 0; i < 4; i++) {  
  130.         writel(0, &regs->laddr[i][LADDR_LOW]);  
  131.         writel(0, &regs->laddr[i][LADDR_HIGH]);  
  132.         /* Do not use MATCHx register */  
  133.         writel(0, &regs->match[i]);  
  134.     }  
  135.   
  136.     writel(macaddrlow, &regs->laddr[0][LADDR_LOW]);  
  137.     writel(macaddrhigh, &regs->laddr[0][LADDR_HIGH]);  
  138.   
  139.     return 0;  
  140. }  
  141.   
  142. static int zynq_gem_init(struct eth_device *dev, bd_t * bis)  
  143. {  
  144.     u32 i;  
  145.     u16 tmp;  
  146.     unsigned long clk_rate = 0;  
  147.     struct phy_device *phydev;  
  148.     const u32 stat_size = (sizeof(struct zynq_gem_regs) -  
  149.                 offsetof(struct zynq_gem_regs, stat)) / 4;  
  150.     struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;  
  151.     struct zynq_gem_priv *priv = dev->priv;  
  152.     const u32 supported = SUPPORTED_10baseT_Half |  
  153.             SUPPORTED_10baseT_Full |  
  154.             SUPPORTED_100baseT_Half |  
  155.             SUPPORTED_100baseT_Full |  
  156.             SUPPORTED_1000baseT_Half |  
  157.             SUPPORTED_1000baseT_Full;  
  158.       
  159.     if (!priv->init) {  
  160.         /* Disable all interrupts */  
  161.         writel(0xFFFFFFFF, &regs->idr);  
  162.   
  163.         /* Disable the receiver & transmitter */  
  164.         writel(0, &regs->nwctrl);  
  165.         writel(0, &regs->txsr);  
  166.         writel(0, &regs->rxsr);  
  167.         writel(0, &regs->phymntnc);  
  168.   
  169.         /* Clear the Hash registers for the mac address 
  170.          * pointed by AddressPtr 
  171.          */  
  172.         writel(0x0, &regs->hashl);  
  173.         /* Write bits [63:32] in TOP */  
  174.         writel(0x0, &regs->hashh);  
  175.   
  176.         /* Clear all counters */  
  177.         for (i = 0; i <= stat_size; i++)  
  178.             readl(&regs->stat[i]);  
  179.   
  180.         /* Setup RxBD space */  
  181.         memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd));  
  182.   
  183.         for (i = 0; i < RX_BUF; i++) {  
  184.             priv->rx_bd[i].status = 0xF0000000;  
  185.             priv->rx_bd[i].addr =  
  186.                     ((u32)(priv->rxbuffers) +  
  187.                             (i * PKTSIZE_ALIGN));  
  188.         }  
  189.         /* WRAP bit to last BD */  
  190.         priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK;  
  191.         /* Write RxBDs to IP */  
  192.         writel((u32)priv->rx_bd, &regs->rxqbase);  
  193.   
  194.         /* Setup for DMA Configuration register */  
  195.         writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);  
  196.   
  197.         /* Setup for Network Control register, MDIO, Rx and Tx enable */  
  198.         setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);  
  199.   
  200.         priv->init++;  
  201.     }  
  202.     printf("phy detection.\n");  
  203.     phy_detection(dev);  
  204.     phy_rst(dev);  
  205.     phy_negotiat(dev);  
  206.       
  207.   
  208.     printf("--------phyaddr : 0x%x----\r\n", priv->phyaddr);  
  209.     unsigned short PhyReg;  
  210.     //change to page 0  
  211.     phyread(dev, priv->phyaddr, 22, &PhyReg);  
  212.     PhyReg = PhyReg & 0xfffe;  
  213.     phywrite(dev, priv->phyaddr, 22, PhyReg);  
  214.   
  215.     phyread(dev, priv->phyaddr, 20, &PhyReg);  
  216.     PhyReg = PhyReg | 0x82;  
  217.     phywrite(dev, priv->phyaddr, 20, PhyReg);  
  218.   
  219.     /*  reset phy    */  
  220.     phyread(dev, priv->phyaddr, 0, &PhyReg);  
  221.     PhyReg |= 0x8000;  
  222.     phywrite(dev, priv->phyaddr, 0, PhyReg);  
  223.   
  224.   
  225.     puts("GEM link speed is 1000Mbps\n");  
  226.     writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, &regs->nwcfg);  
  227.     setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |  
  228.                     ZYNQ_GEM_NWCTRL_TXEN_MASK);   
  229.   
  230.     return 0;  
  231. }  
 

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

[plain]  view plain  copy
  print ?
  1. zynq-uboot> tftp 0x2a00000 devicetree.dtb  
  2. Using zynq_gem device  
  3. TFTP from server 192.168.0.101; our IP address is 192.168.0.99  
  4. Filename 'devicetree.dtb'.  
  5. Load address: 0x2a00000  
  6. Loading: T #  
  7. done  
  8. Bytes transferred = 13222 (33a6 hex)  
  9. zynq-uboot> tftp 0x2000000 uramdisk.image.gz  
  10. Using zynq_gem device  
  11. TFTP from server 192.168.0.101; our IP address is 192.168.0.99  
  12. Filename 'uramdisk.image.gz'.  
  13. Load address: 0x2000000  
  14. Loading: #################################################################  
  15.          #################################################################  
  16.          #################################################################  
  17.          #################################################################  
  18.          #################################################################  
  19.          ####################################  
  20. done  
  21. Bytes transferred = 5289509 (50b625 hex)  
  22. zynq-uboot> tftp 0x3000000 uImage  
  23. Using zynq_gem device  
  24. TFTP from server 192.168.0.101; our IP address is 192.168.0.99  
  25. Filename 'uImage'.  
  26. Load address: 0x3000000  
  27. Loading: T #################################################################  
  28.          #################################################################  
  29.          #################################################################  
  30.          ##########################  
  31. done  
  32. Bytes transferred = 3230680 (314bd8 hex)  
  33. zynq-uboot> bootm 0x3000000 0x2000000 0x2a00000  
  34. ## Booting kernel from Legacy Image at 03000000 ...  
  35.    Image Name:   Linux-4.0.0-dayun  
  36.    Image Type:   ARM Linux Kernel Image (uncompressed)  
  37.    Data Size:    3230616 Bytes = 3.1 MiB  
  38.    Load Address: 00008000  
  39.    Entry Point:  00008000  
  40.    Verifying Checksum ... OK  
  41. ## Loading init Ramdisk from Legacy Image at 02000000 ...  
  42.    Image Name:     
  43.    Image Type:   ARM Linux RAMDisk Image (gzip compressed)  
  44.    Data Size:    5289445 Bytes = 5 MiB  
  45.    Load Address: 00800000  
  46.    Entry Point:  00800000  
  47.    Verifying Checksum ... OK  
  48. ## Flattened Device Tree blob at 02a00000  
  49.    Booting using the fdt blob at 0x02a00000  
  50.    Loading Kernel Image ... OK  
  51. OK  
  52.    Loading Ramdisk to 1faf4000, end 1ffff5e5 ... OK  
  53.    Loading Device Tree to 1faed000, end 1faf33a5 ... OK  
  54.   
  55. Starting kernel ...  
  56.   
  57. Uncompressing Linux... done, booting the kernel.  
  58. Booting Linux on physical CPU 0x0  
  59. 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  
  60. CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d  
  61. CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache  
### 回答1: zynq-linux移植学习笔记应包含以下内容: 1. 对zynq架构和硬件资源的理解,包括PS和PL部分的特点。 2. 如何使用Xilinx SDK来编译和配置u-bootLinux内核。 3. 如何在硬件平台上运行和调试Linux系统。 4. 怎样在Linux系统中配置和使用各种硬件资源,如DMA、Ethernet、Flash等。 5. 如何在Linux系统中移植和运行应用程序,并与硬件资源进行交互。 6. 如何进行系统优化和资源管理,以提高系统性能和稳定性。 ### 回答2: Zynq是一款Xilinx公司开发的一种嵌入式系统芯片,其使用了双核Cortex-A9处理器和可编程逻辑器件(FPGA)的组合。移植LinuxZynq芯片中,可以使其具备无限的扩展能力,极大地拓展了其应用领域,因此掌握Zynq-Linux移植技术是非常重要的。 Zynq-Linux移植分为四个主要步骤: 第一,准备工作 在移植前,需要确认硬件平台是否支持Linux运行,并且需要对硬件进行配置,最好使用Zynq开发板的官方配置; 第二,内核移植 内核移植是整个移植过程中最关键的一步。需要根据硬件平台的特性对内核进行选择和配置。可以从内核源代码库中获取内核代码,然后进行交叉编译。移植内核的过程中需要注意内核配置参数的设置,同时也要确保内核模块和驱动程序的编写。 第三,文件系统移植移植Linux的过程中,文件系统也是非常重要的。可以使用开发板官方Linux镜像,也可以自己编译镜像。移植文件系统还涉及到root文件系统的配置、挂载方式、网络配置和各种服务的配置等问题。 第四,驱动移植 驱动程序是连接硬件和软件的关键部分,需编写相应的驱动程序来实现对硬件的控制。移植驱动程序的过程中需要关注各种硬件接口和设备驱动API的使用,确保驱动程序与硬件配合良好。 总结来说,Zynq-Linux移植技术的掌握需要具备较强的Linux基础知识、驱动开发经验和交叉编译工具链的使用能力。同时,还需要有耐心和细心,对每个步骤进行仔细的分析和处理。 在学习中,需要结合实际开发项目,多进行实践操作才能更好地掌握Zynq-Linux移植技术,为后续项目的开发和应用提供更好的支持。 ### 回答3: Zynq-7000系列是一种由Xilinx开发的SoC(系统级芯片),它将双ARM Cortex-A9处理器和可编程逻辑(FPGA)集成在一起。这使得开发人员可以使用硬件加速加速器来加速运行在Linux上的各种应用。然而,实现这个目标需要进行移植。 在开始Zynq Linux移植学习笔记之前,需要一些基本的知识。首先,需要了解Linux内核的基本工作原理和Linux驱动程序的编写技术。然后,需要了解FPGA和SoC体系结构。 在开始移植之前,需要为SoC开发板选择正确的Linux发行版。这通常需要考虑处理器体系结构,内存大小和设备驱动程序的可用性。另外,还需要考虑是否需要自定义内核或驱动程序以满足应用程序的需求。 接下来,需要编写设备树文件(DT)来描述SoC架构。设备树文件是一种描述硬件配置信息的特殊语言。它会告诉内核有哪些设备可用以及如何访问这些设备。 接下来,需要配置Linux内核以支持Zynq-7000处理器。这可能包括启用适当的内核配置选项,编写设备驱动程序以及配置启动过程。 最后,需要启动Zynq板并验证Linux系统稳定运行。这些步骤包括在启动过程中将设备树文件加载到内存中,以及启动用户空间应用程序。 总之,移植Zynq Linux是一项复杂的任务,需要广泛的专业知识和技术。但是,它可以为开发人员提供强大的硬件加速支持,使他们能够加速处理一系列计算密集型应用程序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值