zoukankan      html  css  js  c++  java
  • Mini440之uboot移植之实践DM9000支持(八)

    继续上一节内容,不知道你有没有注意到,启动u-boot后,运行有一行信息:

    输出Flash信息这一部分代码是位于board_init_r阶段,执行initr_net()函数的输出结果。

    我们开发板上搭载了型号为DM9000网卡芯片,这一节我们将会介绍u-boot如何支持我们的DM9000网卡,这样我们后续就可以通过网络命令下载程序。

    一、DM9000介绍

    关于DM9000的相关内容可以先看<Mini2440裸机开发之DM9000>这篇文章。

    二、DM9000支持

    2.1 宏定义

    在include/configs/smdk2440.h文件有网卡相关的定义,如下:

    /*
     * Hardware drivers
     */
    #define CONFIG_CS8900        /* we have a CS8900 on-board */
    #define CONFIG_CS8900_BASE    0x19000300
    #define CONFIG_CS8900_BUS16    /* the Linux driver does accesses as shorts */

    可以看到u-boot默认的网卡是cs8900。

    2.2  分析启动信息

    在u-boot启动时,我们打印调试信息:

    Net:   Initial value for argc=3
    Final value for argc=3
    CS8900-0
    Error: CS8900-0 address not set.

    我们定位到 initr_net(common/board_r.c):

    static int initr_net(void)
    {
        puts("Net:   ");
        eth_initialize();
    #if defined(CONFIG_RESET_PHY_R)
        debug("Reset Ethernet PHY\n");
        reset_phy();
    #endif
        return 0;
    }

    函数eth_initialize在net/eth_legacy.c中定义:

    int eth_initialize(void)
    {
        int num_devices = 0;
    
        eth_devices = NULL;
        eth_current = NULL;
        eth_common_init();
        /*
         * If board-specific initialization exists, call it.
         * If not, call a CPU-specific one
         */
        if (board_eth_init != __def_eth_init) {
            if (board_eth_init(gd->bd) < 0)
                printf("Board Net Initialization Failed\n");
        } else if (cpu_eth_init != __def_eth_init) {
            if (cpu_eth_init(gd->bd) < 0)
                printf("CPU Net Initialization Failed\n");
        } else {
            printf("Net Initialization Skipped\n");
        }
    
        if (!eth_devices) {
            puts("No ethernet found.\n");
            bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
        } else {
            struct eth_device *dev = eth_devices;
            char *ethprime = getenv("ethprime");
    
            bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
            do {
                if (dev->index)
                    puts(", ");
    
                printf("%s", dev->name);
    
                if (ethprime && strcmp(dev->name, ethprime) == 0) {
                    eth_current = dev;
                    puts(" [PRIME]");
                }
    
                if (strchr(dev->name, ' '))
                    puts("\nWarning: eth device name has a space!"
                        "\n");
    
                eth_write_hwaddr(dev, "eth", dev->index);
    
                dev = dev->next;
                num_devices++;
            } while (dev != eth_devices);
    
            eth_current_changed();
            putc('\n');
        }
    
        return num_devices;
    }

    其中eth_devices、eth_current定义如下:

    static struct eth_device *eth_devices;
    struct eth_device *eth_current;
    struct eth_device {
        char name[16];
        unsigned char enetaddr[6];
        phys_addr_t iobase;
        int state;
    
        int (*init)(struct eth_device *, bd_t *);
        int (*send)(struct eth_device *, void *packet, int length);
        int (*recv)(struct eth_device *);
        void (*halt)(struct eth_device *);
    #ifdef CONFIG_MCAST_TFTP
        int (*mcast)(struct eth_device *, const u8 *enetaddr, u8 set);
    #endif
        int (*write_hwaddr)(struct eth_device *);
        struct eth_device *next;
        int index;
        void *priv;
    };

    2.3 eth_common_init(net/eth_common.c)

    void eth_common_init(void)
    {
        bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
    #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
        miiphy_init();
    #endif
    
    #ifdef CONFIG_PHYLIB
        phy_init();
    #endif
    }

    BOOTSTAGE_ID_NET_ETH_START、BOOTSTAGE_ID_COUNT为枚举类型enum bootstage_id其中的一个元素。这个枚举类型定义了u-boot在启动中的各个阶段,并使用record记录运行到每个阶段时一些信息,比如当前boot时间、id、flags等信息。

    BOOTSTAGE_ID_NET_ETH_START = 64,
    BOOTSTAGE_ID_COUNT = BOOTSTAGE_ID_USER + CONFIG_BOOTSTAGE_USER_COUNT,
    static struct bootstage_record record[BOOTSTAGE_ID_COUNT] = { {1} };

    bootstage_mark在common/bootstage.c中定义:

    static inline ulong bootstage_mark(enum bootstage_id id)
    {
        show_boot_progress(id);
        return 0;
    }

    show_boot_progress函数为空。

    2.4 board_eth_init(board/samsung/smdk2440/smdk2440.c)

    #ifdef CONFIG_CMD_NET    #在include/generated/autoconf.h定义
    int board_eth_init(bd_t *bis)
    {
        int rc = 0;
    #ifdef CONFIG_CS8900
        rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
    #endif
        return rc;
    }
    #endif

    这里根据定义的宏CONFIG_CS8900,执行cs8900_initialize初始化CS8900网卡。

    2.5 cs8900_initialize(drivers/net/cs8900.c)

    int cs8900_initialize(u8 dev_num, int base_addr)
    {
        struct eth_device *dev;
        struct cs8900_priv *priv;
    
        dev = malloc(sizeof(*dev));
        if (!dev) {
            return 0;
        }
        memset(dev, 0, sizeof(*dev));
    
        priv = malloc(sizeof(*priv));
        if (!priv) {
            free(dev);
            return 0;
        }
        memset(priv, 0, sizeof(*priv));
        priv->regs = (struct cs8900_regs *)base_addr;
    
        dev->iobase = base_addr;
        dev->priv = priv;
        dev->init = cs8900_init;
        dev->halt = cs8900_halt;
        dev->send = cs8900_send;
        dev->recv = cs8900_recv;
    
        /* Load MAC address from EEPROM */
        cs8900_get_enetaddr(dev);
    
        sprintf(dev->name, "%s-%hu", CS8900_DRIVERNAME, dev_num);
    
        eth_register(dev);
        return 0;
    }

    这里我们不介绍这部分代码。我们仅仅关注drivers/net路径下的Makefile文件:

    obj-$(CONFIG_CS8900) += cs8900.o

    cs8900是否编译取决于宏CONFIG_CS8900。因此我们如果想支持DM9000网卡,只需要进行部分代码修改即可。

    2.6 代码修改

    修改include/configs/smdk2440.h,把原先的cs8900的宏取消,添加dm9000的宏:

    #if 0
    #define CONFIG_CS8900        /* we have a CS8900 on-board */
    #define CONFIG_CS8900_BASE    0x19000300
    #define CONFIG_CS8900_BUS16    /* the Linux driver does accesses as shorts */
    #else
    #define CONFIG_DRIVER_DM9000
    #define CONFIG_DM9000_BASE 0x20000000         //这三个是新加的
    #define DM9000_IO CONFIG_DM9000_BASE          //这三个是新加的
    #define DM9000_DATA (CONFIG_DM9000_BASE + 4)  //这三个是新加的
    #endif

    网卡属于内存设备,它的片选由写入的地址范围决定。

    从DM9000的文档中可以知道知DM9000的cmd线(即LADDR2线)为0时,数据线做数据寄存器,为1时数据线做地址寄存器。

    因为DM9000的片选是bank4,我们不难从S3C2440的文档中得知其地址是0x20000000开始的,既然LADDR2线控制着数据线的类型,我们只需改变LADDR2的值便可。所以推出DM9000的数据寄存器地址是0x20000000,地址寄存器的地址是0x20000004。

    修改board/samsung/smdk2440/smdk2440.c:

    #ifdef CONFIG_CMD_NET    #在include/generated/autoconf.h定义
    int board_eth_init(bd_t *bis)
    {
        int rc = 0;
    #ifdef CONFIG_CS8900
        rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
    #endif
    #ifdef CONFIG_DRIVER_DM9000
        rc = dm9000_initialize(bis);
    #endif
        return rc;
    }
    #endif

    修改board/samsung/smdk2440/lowlevel_init.S,只需要在那里修改bank4的内容即可:

    .long 0x00000740;    //BANKCON4

    查看drivers/net路径下的Makefile文件,有这么一行:

    obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o

    dm9000x是否编译取决于宏CONFIG_DRIVER_DM9000。

    三、编译下载运行

    3.1 编译

    make distclean
    make smdk2440_config
    make ARCH=arm CROSS_COMPILE=arm-linux- V=1

    3.2 下载到NOR FALSH

    我们再次下载运行,输出如下:

    initcall: 0005da94
    
    
    U-Boot 2016.05 (Nov 29 2021 - 23:20:03 +0800)
    
    initcall: 0000f1b4
    U-Boot code: 00000000 -> 0007F07C  BSS: -> 000CE970
    initcall: 000003f8
    CPUID: 32440001
    FCLK:      400 MHz
    HCLK:      100 MHz
    PCLK:       50 MHz
    initcall: 0000f408
    DRAM:  initcall: 000011f0
    initcall: 0000f358
    Monitor len: 000CE970
    Ram size: 04000000
    Ram top: 34000000
    initcall: 0000ef90
    initcall: 0000f15c
    TLB table from 33ff0000 to 33ff4000
    initcall: 0000efa8
    initcall: 0000f110
    Reserving 826k for U-Boot at: 33f21000
    initcall: 0000f0e4
    Reserving 4160k for malloc() at: 33b11000
    initcall: 0000f30c
    Reserving 80 Bytes for Board Info at: 33b10fb0
    initcall: 0000efb0
    initcall: 0000f0b0
    Reserving 168 Bytes for Global Data at: 33b10f08
    initcall: 0000f038
    initcall: 0000efe4
    initcall: 0000efb8
    initcall: 0000f3f8
    initcall: 0000f284
    
    RAM Configuration:
    Bank #0: 30000000 64 MiB
    
    DRAM:  64 MiB
    initcall: 0000f01c
    New Stack Pointer is: 33b10ee0
    initcall: 0000f248
    initcall: 0000f1e0
    Relocation Offset is: 33f21000
    Relocating to 33f21000, new gd at 33b10f08, sp at 33b10ee0
    initcall: 33f30484
    initcall: 33f3048c
    initcall: 0000f670 (relocated to 33f30670)
    WARNING: Caches not enabled
    initcall: 0000f4a4 (relocated to 33f304a4)
    initcall: 0000f4cc (relocated to 33f304cc)
    initcall: 0000f654 (relocated to 33f30654)
    using memory 0x33b11000-0x33f21000 for malloc()
    initcall: 0000f4d4 (relocated to 33f304d4)
    initcall: 0000f460 (relocated to 33f30460)
    initcall: 0000f640 (relocated to 33f30640)
    initcall: 00001224 (relocated to 33f22224)
    dram_bank_mmu_setup: bank: 0
    initcall: 0001829c (relocated to 33f3929c)
    initcall: 0000f630 (relocated to 33f30630)
    initcall: 0000f598 (relocated to 33f30598)
    Now running in RAM - U-Boot at: 33f21000
    initcall: 0000f4dc (relocated to 33f304dc)
    initcall: 0000f5b4 (relocated to 33f305b4)
    Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
    fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
    fwc addr 00005554 cmd 55 0055 16bit x 16 bit
    fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
    fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
    JEDEC PROBE: ID 1 2249 0
    Found JEDEC Flash: AMD AM29LV160DB
    unlock address index 1
    unlock addresses are 0x555/0x2aa
    erase_region_count = 1 erase_region_size = 16384
    erase_region_count = 2 erase_region_size = 8192
    erase_region_count = 1 erase_region_size = 32768
    erase_region_count = 31 erase_region_size = 65536
    flash_protect ON: from 0x00000000 to 0x00089A33
    protect on 0
    protect on 1
    protect on 2
    protect on 3
    protect on 4
    protect on 5
    protect on 6
    protect on 7
    protect on 8
    protect on 9
    protect on 10
    protect on 11
    flash_protect ON: from 0x00070000 to 0x0007FFFF
    protect on 10
    2 MiB
    initcall: 0000f57c (relocated to 33f3057c)
    NAND:  board_nand_init()
    end of nand_init
    hwcontrol(): 0xff 0x83
    hwcontrol(): 0xffffffff 0x81
    dev_ready
    hwcontrol(): 0x90 0x83
    hwcontrol(): 0x00 0x85
    hwcontrol(): 0xffffffff 0x81
    dev_ready
    hwcontrol(): 0x90 0x83
    hwcontrol(): 0x00 0x85
    hwcontrol(): 0xffffffff 0x81
    dev_ready
    hwcontrol(): 0x90 0x83
    hwcontrol(): 0x40 0x85
    hwcontrol(): 0xffffffff 0x81
    dev_ready
    hwcontrol(): 0xffffffff 0x80
    0 MiB
    initcall: 0000f54c (relocated to 33f3054c)
    *** Warning - bad CRC, using default environment
    
    Destroy Hash Table: 33f9a890 table = 00000000
    Create Hash Table: N=75
    INSERT: table 33f9a890, filled 1/79 rv 33b11238 ==> name="bootdelay" value="5"
    INSERT: table 33f9a890, filled 2/79 rv 33b110f8 ==> name="baudrate" value="115200"
    INSERT: table 33f9a890, filled 3/79 rv 33b110a8 ==> name="ipaddr" value="10.0.0.110"
    INSERT: table 33f9a890, filled 4/79 rv 33b11260 ==> name="serverip" value="10.0.0.1"
    INSERT: table 33f9a890, filled 5/79 rv 33b114f4 ==> name="netmask" value="255.255.255.0"
    INSERT: free(data = 33b11008)
    INSERT: done
    initcall: 0000f474 (relocated to 33f30474)
    initcall: 0001835c (relocated to 33f3935c)
    initcall: 0000f53c (relocated to 33f3053c)
    initcall: 00015fb0 (relocated to 33f36fb0)
    In:    serial
    Out:   serial
    Err:   serial
    Initial value for argc=3
    Final value for argc=3
    Initial value for argc=3
    Final value for argc=3
    Initial value for argc=3
    Final value for argc=3
    initcall: 00000c1c (relocated to 33f21c1c)
    initcall: 0000f52c (relocated to 33f3052c)
    initcall: 0000f50c (relocated to 33f3050c)
    initcall: 0000f4f0 (relocated to 33f304f0)
    Net:   Initial value for argc=3
    Final value for argc=3
    dm9000
    Error: dm9000 address not set.
    
    initcall: 0000f4e4 (relocated to 33f304e4)
    ### main_loop entered: bootdelay=5
    
    ### main_loop: bootcmd="<UNDEFINED>"
    SMDK2440 # 

    报告有错误:dm9000 address not set,MAC地址未设置。对着打印信息查看代码,可以知道打印此条信息的代码是eth_write_hwaddr这个函数,这个函数在eth_initlize中调用:

    int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
               int eth_number)
    {
        unsigned char env_enetaddr[6];
        int ret = 0;
    
        eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
    
        if (!is_zero_ethaddr(env_enetaddr)) {
            if (!is_zero_ethaddr(dev->enetaddr) &&
                memcmp(dev->enetaddr, env_enetaddr, 6)) {
                printf("\nWarning: %s MAC addresses don't match:\n",
                       dev->name);
                printf("Address in SROM is         %pM\n",
                       dev->enetaddr);
                printf("Address in environment is  %pM\n",
                       env_enetaddr);
            }
    
            memcpy(dev->enetaddr, env_enetaddr, 6);
        } else if (is_valid_ethaddr(dev->enetaddr)) {
            eth_setenv_enetaddr_by_index(base_name, eth_number,
                             dev->enetaddr);
        } else if (is_zero_ethaddr(dev->enetaddr)) {
    #ifdef CONFIG_NET_RANDOM_ETHADDR
            net_random_ethaddr(dev->enetaddr);
            printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
                   dev->name, eth_number, dev->enetaddr);
    #else
            printf("\nError: %s address not set.\n",
                   dev->name);
            return -EINVAL;
    #endif
        }
    
        if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
            if (!is_valid_ethaddr(dev->enetaddr)) {
                printf("\nError: %s address %pM illegal value\n",
                       dev->name, dev->enetaddr);
                return -EINVAL;
            }
    
            ret = dev->write_hwaddr(dev);
            if (ret)
                printf("\nWarning: %s failed to set MAC address\n",
                       dev->name);
        }
    
        return ret;
    }
    View Code

    上面定义了一个宏  CONFIG_NET_RANDOM_ETHADDR ,如果定义了此宏的话就会随机分配网卡物理地址,否则就打印错误信息,我们并不需要此宏。自己定义物理地址,从代码流程看,网卡地址是直接写进环境变量中的,然后再读取环境变量,这个时候就需要看看设置环境变量的地方了。

    环境变量的设置在 board_r.c的hash table中,initr_env函数,initr_env 会调用 env_relocate() ,env_relocate() 调用 set_default_env 函数,set_default_env 函数中有一个结构体 default_environment ,这里面定义了默认的参数,进去看看一看就知道里面全部定义的是默认的环境变量参数,其中也有网络的:

    #ifdef    CONFIG_ETHPRIME
        "ethprime="    CONFIG_ETHPRIME            "\0"
    #endif
    #ifdef    CONFIG_IPADDR
        "ipaddr="    __stringify(CONFIG_IPADDR)    "\0"
    #endif
    #ifdef    CONFIG_SERVERIP
        "serverip="    __stringify(CONFIG_SERVERIP)    "\0"

    这里面没有物理地址的定义,所以我们可以自己定义物理地址,在这里加入下面的内容:

    #ifdef    CONFIG_ETHADDR
        "ethaddr="    __stringify(CONFIG_ETHADDR)    "\0"

    在 include/configs/smdk2440.h 中加入 CONFIG_ETHADDR的宏 ,这里我们可以根据自己本机上的MAC地址进行定义。

    #define CONFIG_ETHADDR  08:00:3e:26:0a:5b

    保存编译,下载重新运行,查看结果。

    3.3  shell命令

    更改mac地址:

     set ethaddr 00:0c:29:d3:fe:1d

    ping目标主机:

    ping 192.168.0.104

    如果成功了,试着用网络下载程序试试,在winPC端打开tftp服务器,文件地址写为包含内核的文件地址,在板子上设置服务器ip:

    set serverip 192.168.0.104

    这个ip一定要和tftp服务器上显示的ip一样,向板子输入命令等待传输:

    tftp 30000000 xxx

    烧写完成了,启动程序:

    bootm 30000000

    参考文章

    [1]移植uboot第七步:支持DM9000

    [2]mini2440_dm9000网卡驱动

    [3]u-boot移植(十二)---代码修改---支持DM9000网卡

  • 相关阅读:
    Golang 开发环境安装和配置
    多测师肖老师__接口测试之cms搭建(27.1)
    多测师肖老师__接口测试之fn+f12查看接口(27.2)
    认识wpf中binding类型
    认识wpf的事件
    Jquery对象与Dom对象
    AS3编程中的两种常用事件
    SQL Server 系统表简介
    Winform中ComcoBox控件设置选定项
    wpf开篇入门
  • 原文地址:https://www.cnblogs.com/zyly/p/15622002.html
Copyright © 2011-2022 走看看