上一节分析了命令的实现
我们可以根据自己需要添加一些常用的命令。
之前的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
测试,如下运行完美,毫无卡顿。