zynq u-boot网络配置

原文地址: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启动就可以了。


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是在Zynq U-Boot模式下使用PL网口的详细教程: 1. 首先,确保你的PL设计中有一个可用的以太网控制器,并且已经在硬件中正确连接。同时,需要确保PL网口的物理接口已经与板子上的网络端口连接,可以通过网线连接到交换机或路由器上。 2. 接下来,需要在U-Boot中启用PL网口。可以通过设置U-Boot环境变量来实现。在U-Boot命令行中,使用以下命令定义环境变量: `setenv ethaddr <MAC address>` `setenv ipaddr <IP address>` `setenv serverip <TFTP server IP>` `setenv autoload no` `setenv ethact emacps` `setenv bootargs 'console=ttyPS0,115200 root=/dev/ram rw earlyprintk'` 注意,上面的`ethact`变量需要根据具体硬件和控制器类型进行设置。 3. 定义完环境变量后,需要保存环境变量并重新启动系统。在U-Boot命令行中,使用以下命令: `saveenv` `reset` 4. 系统重启后,需要通过ifconfig命令来配置PL网口。在U-Boot命令行中,使用以下命令: `ifconfig -a` `ifconfig eth0 <IP address>` `ping <IP address>` 注意,上面的`eth0`需要根据具体硬件和控制器类型进行设置。 5. 配置完成后,可以通过ping命令来测试PL网口的连接是否正常。如果一切正常,就可以在U-Boot模式下使用PL网口了。 6. 如果需要在U-Boot中使用TFTP来启动Linux内核,需要将内核文件通过TFTP传输到系统中。在U-Boot命令行中,使用以下命令: `tftpboot <load address> <kernel image name>` `bootm <load address>` 注意,上面的`load address`需要根据具体硬件和内存配置进行设置。 希望以上教程能够帮助你在Zynq U-Boot模式下使用PL网口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值