从零开始之九、移植uboot2017.01(九、网卡移植)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_16777851/article/details/81843354

上一节分析了命令的实现

我们可以根据自己需要添加一些常用的命令。

之前的goni开发板是默认没有使用网卡的,这一节我们尝试移植网卡DM9000在我的板子上。

首先看一下,网络相关的初始化需要哪些宏。

网络相关的初始化在board_r.c中,属于uboot的后半部分。

#ifdef CONFIG_CMD_NET            /* 默认没定义 */
	initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
	board_late_init,
#endif
#if defined(CONFIG_CMD_AMBAPP)
	ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
	initr_ambapp_print,
#endif
#endif
#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
	INIT_FUNC_WATCHDOG_RESET
	initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
	INIT_FUNC_WATCHDOG_RESET
	initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
	initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET        /* 默认没定义 */
	INIT_FUNC_WATCHDOG_RESET
	initr_net,
#endif

通过上面的名字基本可以看到,一个是初始化ethaddr,一个是初始化网卡。

先通过make menuconfig 配置添加CONFIG_CMD_NET  功能        (也可以在smdkv210.h中添加)

 

编译看一下,如果没报错,我们根据串口的输出信息再来修改。

ok,打印出了一些信息我们就根据这些信息慢慢查找。

我们先分析第一个函数initr_ethaddr


#ifdef CONFIG_CMD_NET
static int initr_ethaddr(void)
{
	bd_t *bd = gd->bd;

	/* kept around for legacy kernels only ... ignore the next section */
    /* 我们只有一个网卡芯片,默认也是一个,所以这个没用宏包含的就可以了
     * 可以看到这个是从环境变量里面得到ethaddr的值
     */
	eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
#ifdef CONFIG_HAS_ETH1        /* goni没网卡,网咯相关的宏都没配置 */
	eth_getenv_enetaddr("eth1addr", bd->bi_enet1addr);
#endif
#ifdef CONFIG_HAS_ETH2
	eth_getenv_enetaddr("eth2addr", bd->bi_enet2addr);
#endif
#ifdef CONFIG_HAS_ETH3
	eth_getenv_enetaddr("eth3addr", bd->bi_enet3addr);
#endif
#ifdef CONFIG_HAS_ETH4
	eth_getenv_enetaddr("eth4addr", bd->bi_enet4addr);
#endif
#ifdef CONFIG_HAS_ETH5
	eth_getenv_enetaddr("eth5addr", bd->bi_enet5addr);
#endif
	return 0;
}
#endif /* CONFIG_CMD_NET */

因为我们使用的是默认环境变量,所以我们在默认环境变量里面查看有没有这个环境变量

env_default.c

const uchar default_environment[] = {
#endif
#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	"bootdelay="	__stringify(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="	__stringify(CONFIG_BAUDRATE)	"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
	"loads_echo="	__stringify(CONFIG_LOADS_ECHO)	"\0"
#endif
#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"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
#endif
#ifdef	CONFIG_PREBOOT
	"preboot="	CONFIG_PREBOOT			"\0"
#endif
#ifdef	CONFIG_ROOTPATH
	"rootpath="	CONFIG_ROOTPATH			"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
	"gatewayip="	__stringify(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
	"netmask="	__stringify(CONFIG_NETMASK)	"\0"
#endif
#ifdef	CONFIG_HOSTNAME
	"hostname="	__stringify(CONFIG_HOSTNAME)	"\0"
#endif
#ifdef	CONFIG_BOOTFILE
	"bootfile="	CONFIG_BOOTFILE			"\0"
#endif
#ifdef	CONFIG_LOADADDR
	"loadaddr="	__stringify(CONFIG_LOADADDR)	"\0"
#endif
#ifdef	CONFIG_CLOCKS_IN_MHZ
	"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
	"pcidelay="	__stringify(CONFIG_PCI_BOOTDELAY)"\0"
#endif
#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
	"arch="		CONFIG_SYS_ARCH			"\0"
#ifdef CONFIG_SYS_CPU
	"cpu="		CONFIG_SYS_CPU			"\0"
#endif
#ifdef CONFIG_SYS_BOARD
	"board="	CONFIG_SYS_BOARD		"\0"
	"board_name="	CONFIG_SYS_BOARD		"\0"
#endif
#ifdef CONFIG_SYS_VENDOR
	"vendor="	CONFIG_SYS_VENDOR		"\0"
#endif
#ifdef CONFIG_SYS_SOC
	"soc="		CONFIG_SYS_SOC			"\0"
#endif
#endif
#ifdef	CONFIG_EXTRA_ENV_SETTINGS
	CONFIG_EXTRA_ENV_SETTINGS
#endif
	"\0"
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
	}
#endif
};

可以看到,默认环境里面其实还是要自己定义的,而且上面也没有ethaddr这个环境变量,这里我们等会就要在smdkv210.h中和默认环境变量数组中都要定义了。

接下来我们分析第二个函数。

#ifdef CONFIG_CMD_NET
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;
}
#endif

可以看到打印信息我们看到的一致,接下来就看真正的初始化函数eth_initialize

从sourceInsight看发现有两个eth_initialize函数

查看net目录下的Makefile文件

我们没定义网络设卡的设备树CONFIG_DM_ETH

所以我们是调用 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) {    /* 不一样则调用board_eth_init  */
		if (board_eth_init(gd->bd) < 0)
			printf("Board Net Initialization Failed\n");
	} else if (cpu_eth_init != __def_eth_init) {     /* 不一样则调用cpu_eth_init*/
		if (cpu_eth_init(gd->bd) < 0)
			printf("CPU Net Initialization Failed\n");
	} else {
		printf("Net Initialization Skipped\n");        /* 上面打印出来了这句,说明前面两个if都没执行 */
	}

	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;
}

搜索board_eth_init,发现它定义在该文件的最上面。发现是一个weak属性,即弱属性,作用是在其他地方有定义,则使用别的地方定义的,这里的无效。

通过打印信息可以看到下面三个函数都相等,所以他们俩个都没有被没有定义。

board_eth_init
cpu_eth_init
__def_eth_init

函数都没定义,自然不能被初始化。

所以我们要自己实现上面的的函数,搜索board_eth_init,看其他板子有没有实现。

发现smdkc100有使用网卡,都是三星的板子,很接近我们就参考smdkc100实现一个board_eth_init函数

smdkc100这cmdkc100.c中定义,我们将来定义到smdkv210.c中


int board_eth_init(bd_t *bis)
{
	int rc = 0;
#ifdef CONFIG_SMC911X        /* 比较可惜,不是dm9000 */
	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
	return rc;
}

因为smdkc100不是用的dm9000网卡,所以,我们可参考的价值不多。

先找到dm9000x.c文件,找到初始化函数(在.c文件的末尾)

int dm9000_initialize(bd_t *bis)
{
	struct eth_device *dev = &(dm9000_info.netdev);

	/* Load MAC address from EEPROM */
	dm9000_get_enetaddr(dev);

	dev->init = dm9000_init;
	dev->halt = dm9000_halt;
	dev->send = dm9000_send;
	dev->recv = dm9000_rx;
	strcpy(dev->name, "dm9000");

	eth_register(dev);

	return 0;
}

在smdkv210.c中仿照smdkc100.c移植


int board_eth_init(bd_t *bis)
{
	int rc = 0;
#ifdef xxxxx        /*  这里依赖dm9000的宏 */
	rc = dm9000_initialize(bis);    /* 注意传参 */
#endif
	return rc;
}

在driver/net/Makefile中查看,dm9000x依赖CONFIG_DRIVER_DM9000,所以在board_eth_init中添加,同时要在smdkv210.h中添加


int board_eth_init(bd_t *bis)
{
	int rc = 0;
#ifdef CONFIG_DRIVER_DM9000        /*  这里依赖dm9000的宏 */
	rc = dm9000_initialize(bis);    /* 注意传参 */
#endif
	return rc;
}

dm9000和smc9115都是依赖rom实现的网卡 

在smkc100.c中还初始化了对应的rom

/* 通过简单分析,在smdkc100中smc9115接在CONFIG_ENV_SROM_BANK上,初始化对应的cs接口,以及
 * 数宽度,延时等参数,查看smdkc100.h  CONFIG_ENV_SROM_BANK等于1,表明我我们一样是接在bank1上的
 */
static void smc9115_pre_init(void)
{
	u32 smc_bw_conf, smc_bc_conf;

	/* gpio configuration GPK0CON */
	gpio_cfg_pin(S5PC100_GPIO_K00 + CONFIG_ENV_SROM_BANK, S5P_GPIO_FUNC(2));

	/* Ethernet needs bus width of 16 bits */
	smc_bw_conf = SMC_DATA16_WIDTH(CONFIG_ENV_SROM_BANK);
	smc_bc_conf = SMC_BC_TACS(0x0) | SMC_BC_TCOS(0x4) | SMC_BC_TACC(0xe)
			| SMC_BC_TCOH(0x1) | SMC_BC_TAH(0x4)
			| SMC_BC_TACP(0x6) | SMC_BC_PMC(0x0);

	/* Select and configure the SROMC bank */
	s5p_config_sromc(CONFIG_ENV_SROM_BANK, smc_bw_conf, smc_bc_conf);
}

int board_init(void)
{
	smc9115_pre_init();

	gd->bd->bi_arch_number = MACH_TYPE_SMDKC100;
	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

	return 0;
}

参考smc9115的格式,移植我们的dm9000


#ifdef CONFIG_DRIVER_DM9000
static void dm9000_pre_init(void)
{
    u32 smc_bw_conf, smc_bc_conf;

    /* gpio configuration GPK0CON */
    gpio_cfg_pin(S5PC110_GPIO_MP010 + CONFIG_ENV_SROM_BANK, S5P_GPIO_FUNC(2));

    /* 下面几个参数,先和前面的一样,后面分析了再改 */
	/* gpio configuration GPK0CON */
	gpio_cfg_pin(S5PC100_GPIO_K00 + CONFIG_ENV_SROM_BANK, S5P_GPIO_FUNC(2));

	/* Ethernet needs bus width of 16 bits */
	smc_bw_conf = SMC_DATA16_WIDTH(CONFIG_ENV_SROM_BANK);
	smc_bc_conf = SMC_BC_TACS(0x0) | SMC_BC_TCOS(0x4) | SMC_BC_TACC(0xe)
			| SMC_BC_TCOH(0x1) | SMC_BC_TAH(0x4)
			| SMC_BC_TACP(0x6) | SMC_BC_PMC(0x0);

    /* Select and configure the SROMC bank */
    s5p_config_sromc(CONFIG_ENV_SROM_BANK, smc_bw_conf, smc_bc_conf);
}
#endif



int board_init(void)
{
#ifdef CONFIG_DRIVER_DM9000
    dm9000_pre_init();
#endif

    /* Set Initial global variables */
    gd->bd->bi_arch_number = MACH_TYPE_SMDKV210;
    gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

    return 0;
}

在smdkv210.h中添加

#define CONFIG_DRIVER_DM9000                  /* 使用dm9000驱动 */
#define #define CONFIG_ENV_SROM_BANK 1        /* 使用srom的bank1 */

编译

make clean
make -j4

忘记添加dm9000相关的宏了。

S5PV210 的 SROM 控制器支持 8/16 位  NOR  Flash/PROM/SRAM 内存。分为 6 个 bank,每个 bank 寻址空间 128MB。每个 bank 有一个片选信号 nGCS[5:0],用来选通外接的内存芯片。当发的地址在bank1 的寻址范围类(0x88000000~0x8FFFFFFF)时,表示在访问 bank1,此时 nGCS1 信号被拉低,这就选中了接在 bank1 上的 DM9000A 网卡芯片。S5PV210 手册给出了每个 bank 的地址空间:

查看数据手册,bank1的基址是0x88000000

查看原理图,我们采用的是16bit数据线的,CMD口接的是addr2

当对某个地址进行读操作时, S5PV210 的 Xm0OEn 信号被自动拉低,这个信号引脚接在 DM9000A 的nIOR 上,这就对 DM9000A 进行了读使能,可以从 DM9000A 读数据;当对某个地址进行写操作时,S5PV210 的 Xm0WEn 信号被自动拉低,这个信号引脚接在 DM9000A 的 nIOW 上,这就对 DM9000A进行了写使能,可以向 DM9000A 写数据。DM9000A 的 16 根数据线全部接在 S5PV210 的数据线上。DM9000A 包含一系列可被访问的控制状态寄存器,这些寄存器是字节对齐的,他们在硬件或软件复位时被设置成初始值。DM9000A 有 2 个端口:DATA 和 INDEX(即地址) 。DM9000A 的地址和数据线复用, 当 CMD 引脚为低电平时,操作的是 INDEX 端口,当 CMD 引脚为高电平时操作的是 DATA 端口。CMD 引脚接在 S5PV210 的地址线 Xm0ADDR2 上。

地址线只用了一根,用来判断是地址还是数据的。

假设要读取 DM9000A 的寄存器 RSR(RX Status Register),需要分 2 步:
     1)  向 INDEX 端口写入 RSR 寄存器的地址(0x06)

      条件: nGCS1 信号拉低、 Xm0WEn 信号拉低、 Xm0ADDR2 拉低, 或者说向(0x88000000~0x8FFFFFFF)& ~(1 << 2)地址写dm9000的地址 0x06
     2)  从 DATA 端口读取 RSR 寄存器的值
      条件:nGCS1 信号拉低、Xm0OEn 信号拉低、Xm0ADDR2 拉高,或者说从(0x88000000~0x8FFFFFFF)|  (1 << 2)地址读dm9000的数据

假设要向 DM9000A 的寄存器 TCR(TX Control Register)写数据 0x56,同样需要 2 步
       1)  向 INDEX 端口写入 TCR 寄存器的地址(0x02)
         条件: nGCS1 信号拉低、 Xm0WEn 信号拉低、 Xm0ADDR2 拉低, 或者说向0x02(0x88000000~0x8FFFFFFF)&   ~(1 << 2) 地址写dm9000的地址02 
      2)  将要写入的数据(0x56)写入 DATA 端口
        条件: nGCS1 信号拉低、 Xm0WEn 信号拉低、 Xm0ADDR2 拉高,或者说向(0x88000000~0x8FFFFFFF)|  (1 << 2)地址写数据 0x56

  

有了上面的一点基本概念,下面的分析可以简单一些。

上面分析过,DM9000A 的 16 根数据线全部接在 S5PV210 的数据线上,所以 DataWidth1 设置为 1,DM9000A 的地址是按字节存取的,所以 AddrMode1 设置为 1,通过查看原理图,我们使用 Xm0WAITn和 Xm0BEn 引脚了,所以WaitEnable1 和 ByteEnable1 均设置为 1
       SROM_BW[7:4]=0xf;

接下来了解一下时序

S5PV210的读

dm9000的读

上面 2 个时序图分别为 S5PV210 的 SROM 控制器读时序和 DM9000A 的读时序:
Tacs:地址发出后等多长时间发片选,DM9000A 中 CS 和 CMD(地址)同时发出,所以 Tacs=0ns
Tcos:发出片选信号后等多长时间发出读使能信号(nOW、IOR) ,在 DM9000A 的时序图上对应 T1,
最小为 0,为了可靠我们可以设大一些5ns
Tacc:读使能信号持续时间,在 DM9000A 的时序图上对应 T2,最小为10ns,为了可靠我们可以设大一些15us
Tcoh:读使能信号结束后,片选信号保持时间,在 DM9000A 的时序图中对应 T5,最小为0ns,为了可靠我们可以设大一些
Tcoh=5ns
Tcah:片选结束后,地址保存时间,DM9000A 中片选和地址同时结束,所以 Tcah=0
Tacp:(dm9000没有不管)
PMC:(dm9000没有不管)

S5PV210 的 SROM 控制器使用 MSYS 域提供 HCLK 时钟,我们主频设置的1G,MSYS域的HCLK为 200MHz,所以一个 clock 为 5ns。

从手册上kan看,所有的时间参数都是按clock来计算的。即一个clock = 5us

根据计算的时间,修改上面的时间参数。

static void dm9000_pre_init(void)
{
    u32 smc_bw_conf, smc_bc_conf;

     
	/* gpio configuration GPK0CON */
	gpio_cfg_pin(S5PC110_GPIO_K00 + CONFIG_ENV_SROM_BANK, S5P_GPIO_FUNC(2));

	/* Ethernet needs bus width of 16 bits */
	smc_bw_conf = SMC_DATA16_WIDTH(CONFIG_ENV_SROM_BANK)    |   
                    SMC_BYTE_ADDR_MODE(CONFIG_ENV_SROM_BANK)|
                    SMC_WAIT_ENABLE(CONFIG_ENV_SROM_BANK)   |   
                    SMC_BYTE_ENABLE(CONFIG_ENV_SROM_BANK);

	smc_bc_conf = SMC_BC_TACS(0x0) | SMC_BC_TCOS(0x1) | SMC_BC_TACC(0x3)
                | SMC_BC_TCOH(0x1) | SMC_BC_TAH(0x0)
                | SMC_BC_TACP(0x0) | SMC_BC_PMC(0x0);

    /* Select and configure the SROMC bank */
    s5p_config_sromc(CONFIG_ENV_SROM_BANK, smc_bw_conf, smc_bc_conf);
}

smdkv210.h中添加

#ifdef CONFIG_CMD_NET
#define CONFIG_DRIVER_DM9000                  /* 使用dm9000驱动 */
#define #define CONFIG_ENV_SROM_BANK 1        /* 使用srom的bank1 */

#define CONFIG_DM9000_BASE  0x88000000        
#define DM9000_IO           CONFIG_DM9000_BASE
#define DM9000_DATA         (CONFIG_DM9000_BASE + 4)
#define CONFIG_DM9000_USE_16BIT  1
#endif

编译下载看能不能启动

Net有了,地址没设置,ok,我们看一下这句话是在那里打印的。

在eth_initialize里面的eth_write_hwaddr里面打印出来的,从名字可以看出这个是设置硬件地址,即MAC地址的


int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
		   int eth_number)
{
	unsigned char env_enetaddr[6];
	int ret = 0;

    /* 得到ethaddr从环境变量 */
	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                    /* 如果定义这个宏的话随机生成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",    /* 我们在这里打印出来的dm9000地址没设 */
		       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);       /* 写入环境变量把最终通过的mac地址 */
		if (ret)
			printf("\nWarning: %s failed to set MAC address\n",
			       dev->name);
	}

	return ret;
}

因为goni默认是没网络相关的配置,所以ethaddr肯定是环境变量里面没有的。

从上面代码分析可以看到,我们有两种方式设置ethaddr地址。

一种是代码中添加固定的环境变量ethaddr,另一种是添加配置宏CONFIG_NET_RANDOM_ETHADDR,让系统随机生成。

可以先添加CONFIG_NET_RANDOM_ETHADDR使用系统随机生成的配置尝试一下。

可以看到上面已经生成了MAC地址,没有了前面的address no set。但这个现实的warning仍然让我这个完美主义者有点不爽,那么就继续我们自己在环境变量里面添加一个。

在include/env_default.c里面的默认环境变量中添加,格式参考CONFIG_LOADADDR

#ifdef  CONFIG_LOADADDR
    "loadaddr=" __stringify(CONFIG_LOADADDR)    "\0"
#endif
#ifdef  CONFIG_ETHADDR  
    "ethaddr=" __stringify(CONFIG_ETHADDR) "\0"
#endif

同时在smdkv210.h中添加

#define CONFIG_ETHADDR      01:23:45:67:89:ab

ok,没有告警,现在我们尝试一下ping能不能ping通我们的ubuntu主机。

我擦,不认识ping 命令

make menuconfig
    Command line interface  ---> 
        Network commands  --->   

添加几个我们常用的。

再次测试。

各种问题啊,连dm9000的id都没读出来。

三天后...........

各种熬夜,从头开始捋,问题终于找到来。

原因就两个字,坑爹!!


     /* CLK_IP1 */
     ldr r1, =0xe9fdf0f9         @ FIMD[0] USBOTG[16]
                                 @ NANDXL[24]
     str r1, [r0, #0x464]        @ S5PC110_CLK_IP1

原因就发生在lowlevel_init.S中的这句初始化时钟钟指令。

从寄存器手册我们知道了SROM的时钟开关是通过bit26实现的。

而控制bit[24~27]的值在C110的初始化里默认是0x9,即只开了bit24和bit27的时钟。

SROM的时钟是关着的,所以它读取dm9000的任何东西都肯定读不到。

真的是坑啊。

吃出一堑长一智,今后硬件调试顺序硬要清晰。

1.确定时钟OK

2.确定对应硬件IO初始化OK

3.确定硬件外设OK

4.应用测试OK

更改后

    /* CLK_IP1 */
#   ldr r1, =0xe9fdf0f9         @ FIMD[0] USBOTG[16]
    ldr r1, =0xedfdf0f9         @ FIMD[0] USBOTG[16]   to_run_away add. srom  clock open
                                @ NANDXL[24]
                                @ SROMC[26]            to_run_away add. srom  clock open
    str r1, [r0, #0x464]        @ S5PC110_CLK_IP1

可以看到这次dm9000的id读到了。

我们随便给的MAC地址好像有错,好吧,uboot里面随便搜一个用吧。

#define CONFIG_ETHADDR      00:19:D3:FF:FF:FF

编译测试如下:

因为我们没指定ipaddr,所以要设置一个后才能ping

可以看到,这次我们终于网络测试ok了。

尝试ftfp下载一个文件试一下。

好多东西没设啊,我们参考有网络配置的板子,统一定义默认值,写入板子把,不然每次设置也很烦。

添加到smdkv210.h

#ifdef CONFIG_CMD_NET
#define CONFIG_NET_RANDOM_ETHADDR
#define CONFIG_NETMASK  255.255.255.0
#define CONFIG_SERVERIP 192.168.0.107
#define CONFIG_GATEWAYIP    192.168.0.1
#define CONFIG_IPADDR   192.168.0.100
#endif

测试,如下运行完美,毫无卡顿。

猜你喜欢

转载自blog.csdn.net/qq_16777851/article/details/81843354