之前已经将板子设为NAND启动了,但这只是能从NANDcopy代码,不代表板子就支持了以后对NANDFlash的读写操作。
启动板子以后输出信息:
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
### ERROR ### Please RESET the board ###
其中说明了Flash: *** failed ***
,表示确实flash没有支持。
一. 复制这个错误到到SI中搜索,结果如下:
#if !defined(CONFIG_SYS_NO_FLASH)
puts("Flash: ");
flash_size = flash_init();
if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
char *s = getenv("flashchecksum");
print_size(flash_size, "");
/*
* Compute and print flash CRC if flashchecksum is set to 'y'
*
* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
*/
if (s && (*s == 'y')) {
printf(" CRC: %08X", crc32(0,
(const unsigned char *) CONFIG_SYS_FLASH_BASE,
flash_size));
}
putc('\n');
# else /* !CONFIG_SYS_FLASH_CHECKSUM */
print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts("0 KB\n\r");
puts(failed);
hang();
}
#endif
可以知道是if语句不成立,导致输出failed,也就是说读取flash大小的时候flash_size值为0。
先把这两句话注释掉
puts(failed);
hang(); //表示阻塞中,程序到这里就死循环
进入nand初始化函数flash_init();
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
/* Optionally write flash configuration register */
cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
cfi_flash_config_reg(i));
if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
flash_get_size(cfi_flash_bank_addr(i), i);
size += flash_info[i].size;
这里可以看到Flash的大小是由size 这个变量决定的。
进入flash_get_size(),看到里面有一些debug
debug ("manufacturer is %d\n", info->vendor);
debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
debug ("device id is 0x%x\n", info->device_id);
debug ("device id2 is 0x%x\n", info->device_id2);
debug ("cfi version is 0x%04x\n", info->cfi_version);
二. JEDEC PROBE: ID c2 2249 0 这句话其中的c2表示厂家ID,2249表示机器ID。查阅NORFlash手册,发现这两个ID是正确的,但是没有检测到,说明程序底层驱动是对的,但是板子没支持这个NOR。搜索JEDEC PROBE:
flash_read_jedec_ids(info);
debug("JEDEC PROBE: ID %x %x %x\n",
info->manufacturer_id,
info->device_id,
info->device_id2);
if (jedec_flash_match(info, info->start[0]))
break;
else
unmap_physmem((void *)info->start[0],MAP_NOCACHE);
进入jedec_flash_match函数:
/*-----------------------------------------------------------------------
* match jedec ids against table. If a match is found, fill flash_info entry
*/
int jedec_flash_match(flash_info_t *info, ulong base)
{
int ret = 0;
int i;
ulong mask = 0xFFFF;
if (info->chipwidth == 1)
mask = 0xFF;
for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
(jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
fill_info(info, &jedec_table[i], base);
ret = 1;
break;
}
}
return ret;
}
进入jedec_table数组查看:
static const struct amd_flash_info jedec_table[] = {
#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
{
.mfr_id = (u16)SST_MANUFACT,
.dev_id = SST39LF020,
.name = "SST 39LF020",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_256KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x01000,64),
}
},
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
{
.mfr_id = (u16)AMD_MANUFACT,
.dev_id = AM29LV040B,
.name = "AMD AM29LV040B",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000,8),
}
},
{
.mfr_id = (u16)SST_MANUFACT,
.dev_id = SST39LF040,
.name = "SST 39LF040",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x01000,128),
}
},
{
.mfr_id = (u16)STM_MANUFACT,
.dev_id = STM_ID_M29W040B,
.name = "ST Micro M29W040B",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000,8),
}
},
{
.mfr_id = (u16)MX_MANUFACT,
.dev_id = MX29LV040,
.name = "MXIC MX29LV040",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000, 8),
}
},
{
.mfr_id = (u16)WINB_MANUFACT,
.dev_id = W39L040A,
.name = "WINBOND W39L040A",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000, 8),
}
},
{
.mfr_id = (u16)AMIC_MANUFACT,
.dev_id = A29L040,
.name = "AMIC A29L040",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000, 8),
}
},
{
.mfr_id = (u16)EON_MANUFACT,
.dev_id = EN29LV040A,
.name = "EON EN29LV040A",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x10000, 8),
}
},
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
{
.mfr_id = (u16)AMD_MANUFACT,
.dev_id = AM29F400BB,
.name = "AMD AM29F400BB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_512KiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x04000, 1),
ERASEINFO(0x02000, 2),
ERASEINFO(0x08000, 1),
ERASEINFO(0x10000, 7),
}
},
{
.mfr_id = (u16)AMD_MANUFACT,
.dev_id = AM29LV400BB,
.name = "AMD AM29LV400BB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_512KiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x04000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x08000,1),
ERASEINFO(0x10000,7),
}
},
{
.mfr_id = (u16)AMD_MANUFACT,
.dev_id = AM29LV800BB,
.name = "AMD AM29LV800BB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_1MiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x04000, 1),
ERASEINFO(0x02000, 2),
ERASEINFO(0x08000, 1),
ERASEINFO(0x10000, 15),
}
},
{
.mfr_id = (u16)STM_MANUFACT,
.dev_id = STM29F400BB,
.name = "ST Micro M29F400BB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_512KiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions = 4,
.regions = {
ERASEINFO(0x04000, 1),
ERASEINFO(0x02000, 2),
ERASEINFO(0x08000, 1),
ERASEINFO(0x10000, 7),
}
},
#endif
};
查询以后发现,确实是这里面没有我们所使用的NORFlash。
进入机器ID的宏定义代码,里面找到了这个:
#define MX_MANUFACT 0x00C200C2 /* MXIC manuf. ID in D23..D16, D7..D0 */
C2就是我们使用的NORFlash,说明uboot是能够支持的,只是数组中没有将其写入。更改数组,加入我们自己的NORflash,使其能够支持。
因为数组中有宏定义,我也不打算破坏它的结构了,随便复制了一个将其粘贴到数组的最后端,#endif的下面。
{
.mfr_id = (u16)SST_MANUFACT,
.dev_id = SST39LF020,
.name = "SST 39LF020",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_256KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x01000,64),
}
},
a.将厂家ID:mfr_id修改为MX_MANUFACT,
b.机器ID:dev_id修改为0x2249,
c.名字:name修改为"MXIC MT29LV160DB"
uaddr解锁地址改为[1] = MTD_UADDR_0x0555_0x02AA /* x16 */ /*NOR flash 解锁地址 */
[0]表示NOR是8位的,我使用的是16位的,因此改为1。NORFlash使用的时候会锁定,因此写的时候要先解锁,在一些地址中写入值才能解锁。解锁地址可以查阅手册。
d.大小:DevSize修改为SIZE_2MiB
e.NumEraseRegions改为4。
NOR的结构不同,擦除块是不同的,例如一个flash可能分成了十块,每块128kb,也有可能一个flash前十块是128kb,后十块是256kb,可以查阅手册,有多少种块,就写几,我使用的NOR有4中,分别8字节2块,16字节1块,32字节1块,64字节31块。
regions = {
ERASEINFO(0x01000,64),
}
修改为:
.regions = {
ERASEINFO(16 * 1024 , 1),
ERASEINFO(8 * 1024 , 2),
ERASEINFO(32 * 1024 , 1),
ERASEINFO(64 * 1024 , 31),
}
这个就是说明擦除块的分布情况,从上往下分别是NOR中地址从低到高排布。
make,烧写,运行。
出现警告,说擦除块太多。查看以后是宏定义值为19,值小于我们的擦除块数量,将其修改为128。 其实这个值多少都可以,只要大于使用的擦除块就行了。
三. 调试时出现一个bug,对移植来说关联不大,但是很有可能在以后造成错误,这里就把它修改一下。
重定位的时候东西都移了,但是栈指针没有修改,要重新设置栈,否则所有的东西都在0x33F00000,只有栈在0x30000000,在0x33F00000之前是考虑空出来了一块区域给栈用的,现在没有重新定位栈,导致都没有用。程序能跑,但是这样的话,要时刻小心不能使用0x30000000之后的这块区域,否则修改到变量了,uboot很有可能会死。
在start.S中设置一个全局变量
.globl base_sp
base_sp:
.long 0
board_init_f函数本质上是一个计算uboot存放位置的函数,在这里可以找到为栈设置的地址。
base_sp = addr_sp;
在重定位代码以后,将栈指针重新设置
ldr r1, _TEXT_BASE
ldr sp, base_sp /* 重新设置栈 */
/* 调用第二阶段代码 */
bl board_init_r
编译,烧写,运行。
U-Boot 2012.04.01 (Aug 12 2016 - 00:17:17)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: fwc addr (null) 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 (null) cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
2 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
成功了