前不久买了阳初2440超值板,价格算是便宜,但基本没有技术服务,原来还有个论坛现在都关了,真是不责任啊!
我前面已经尝试过将板子上的64M Flash换为大容量的,发现2440不支持MLC的ECC,而同为SLC结构的8位NAND Flash,128M以下的主要是512字节页面,128M以上的为2K页面,就是因为页面大小的不同,导致换上去的512M Flash不能正常引导了。
查看vivi2440_src/include/mtd/nand_ids.h中是包含对512M Flash支持的,只是pagesize, pageadrlen, erasesize对应的域均为0。开始以为是这个地方的问题,后来发现vivi2440_src/drivers/mtd/nand/smc_core.c中的函数int smc_scan(struct mtd_info *mtd)有:
#ifdef USE_256BYTE_NAND_FLASH
if (!mtd->size) {
mtd->name = nand_flash_ids[i].name;
mtd->erasesize = nand_flash_ids[i].erasesize;
mtd->size = (1 << nand_flash_ids[i].chipshift);
mtd->eccsize = 256;
if (nand_flash_ids[i].pagesize == PAGESIZE256) {
mtd->oobblock = 256;
mtd->oobsize = 8;
this->page_shift = 8;
} else {
mtd->oobblock = 512;
mtd->oobsize = 16;
this->page_shift = 9;
}
this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
}
#else
if (!(nand_flash_ids[i].pagesize)) {
int extid;
/* The 3rd id byte contains non relevant data ATM */
extid = this->read_data();
/* The 4th id byte is the important one */
extid = this->read_data();
/* Calc pagesize */
mtd->oobblock = 1024 << (extid & 0x3);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
//busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
mtd->name = nand_flash_ids[i].name;
mtd->size = (1 << nand_flash_ids[i].chipshift);
mtd->eccsize = 256;
this->page_shift = 11;
this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
this->badblockpos = 0;
} else if (!(mtd->size) && (nand_flash_ids[i].pagesize != PAGESIZE256)) {
mtd->name = nand_flash_ids[i].name;
mtd->erasesize = nand_flash_ids[i].erasesize;
mtd->size = (1 << nand_flash_ids[i].chipshift);
mtd->eccsize = 256;
mtd->oobblock = 512;
mtd->oobsize = 16;
this->page_shift = 9;
this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
this->badblockpos = 5;
}
#endif
/* Do not replace user supplied command function ! */
if ((mtd->oobblock>512) && (this->cmdfunc == nand_command))
this->cmdfunc = nand_command_lp;
|
在预编译指令#ifdef USE_256BYTE_NAND_FLASH
的#else
处检查nand_flash_dev的结构的pagesize为0,表示pagesize等域要从Flash芯片内扩展id读出,具体细节查看芯片手册。
为追根溯源,干脆直接读vivi2440_src/arch/s3c2440/head.S源码,从Reset标签往下读,CPU执行完一系列的初始化工作(如内存管理、串口设备初始化)之后,终于执行到一个关键的封地方:
这里可以看作为bootloader的Stage1和Stage2的分界点,实际上应为这个函数执行后紧接着的跳转,即:
@ jump to ram
ldr r1, =on_the_ram
add pc, r1, #0
|
从字面就可以看出,copy_myself函数把vivi自身从启动设备(Nor Flash或NAND Flash)拷贝到内存中。再查看copy_myself,执行了一系列初始化Flash接口的初始化之后:
#ifndef CONFIG_S3C2440_NAND_BOOT
ldr r2, =__bss_start
ldr r0, =__ro_start
mov r1, sl
sub r2,r2,r0
ldmfd sp!,{lr}
b mem_copy
#else @ #ifdef CONFIG_S3C2440_NAND_BOOT
@ copy vivi to RAM
@ldr r0, =VIVI_RAM_BASE
@mov r1, #0x0
@mov r2, #0x20000
@mov r0, #'R'
@bl PrintChar
ldr r2, =__bss_start
ldr r0, =__ro_start
movs r1, sl
@mov r1, #0
sub r2,r2,r0
ldmnefd sp!,{lr}
bne mem_copy
bl nand_read_ll
|
会根据配置文件vivi2440_src/include/autocong.h中的宏CONFIG_S3C2440_NAND_BOOT
是否定义来决定执行mem_copy
(如从Nor Flash中拷贝)还是nand_read_ll
,只是没有太弄明白__bss_start和__ro_start这两个内置标签的地址是怎么被确定的,因为即便在定义了宏CONFIG_S3C2440_NAND_BOOT
的情况下,也有可能执行mem_copy
的。这种情况就是板子设置为上电从Nor Flash中启动,而且vivi也保存在Nor Flash中,而操作系统内核保存在Nand Flash中,这也是很常见的情况。所以一般即使我们把板子的跳线设为从Nor Flash启动,实际上还是应该配置vivi为Support NAND Boot,因为我们不太可能将操作系统内核放在Nor Flash中的。但是问题是怎么控制执行到
这个地方还不是很清楚。
我们可以先来看nand_read_ll
函数,它定义在vivi2440_src/arch/nand_read.c中,这个函数注释为:/* low level nand read function */,也就是vivi在Stage1中会用到,所以要注意这个函数中最好不要调用非low level的函数,比如printf,因为我们可以考虑一下,如果vivi存放在NAND中,在vivi的Stage1只有4K的代码在内部RAM中,你调用的非low level函数极可能不在RAM中。不过,还没有弄清楚怎么控制编译器将这些low level函数放入目标文件的前4K位置。为了替代printf来帮助调试,head.S中定义了PrintChar、PrintWord和PrintHexWord等函数用来向串口终端打印字符,调试的printk应该也不能用,我们可以查看vivi2440_src/vivi.map文件,可以看到目标文件的所有函数入口点的地址(这个地址是加载到内存之后的地址),Stage1中可用的函数入口点都位于33f00000和33f00fff地址之间(反之不成立)。
这个版本的vivi实际上支持2k页面的NAND Flash的引导,只需要开启nand_read.c页面顶部LARGEPAGE_FLASH的宏定义:
//#define LARGEPAGE_FLASH
|
不过读取逻辑实现得不是很好,坏块检查只能在读取之前进行一次,读取过程中没有再检查。原代码如下:
#define PAGESPERSBLOCK (32)
#define BYTESPERSPAGE (512)
#define NAND_BLOCK_SMASK (512 - 1)
#define PAGESPERLBLOCK (64)
#define NAND_BLOCK_LMASK (2048 - 1)
#ifndef LARGEPAGE_FLASH
#define NAND_SECTOR_SIZE 512
#else
#define NAND_SECTOR_SIZE 2048
#endif
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
void PrintChar(char msg);
static int maf_id,dev_id;
/* low level nand read function */
int nand_block_checkbad_ll(unsigned long addr);
void PrintChar(char msg);
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int j, n;
unsigned long addr,baddr;
//PrintChar('r');
if ((start_addr & NAND_BLOCK_MASK)/* || (size & NAND_BLOCK_MASK)*/) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
baddr=start_addr;
while(size>0) {
if (!nand_block_checkbad_ll(baddr)) {
for (j=0;j<size;j+=NAND_SECTOR_SIZE) {
/* READ0 */
NAND_CLEAR_RB;
NFCMD = NAND_CMD_READ0;
addr = baddr+j;
/* Write Address */
#ifndef LARGEPAGE_FLASH
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
#else
NFADDR = addr & 0xff;
NFADDR = (addr >> 8) & 0x07;
NFADDR = (addr >> 11) & 0xff;
NFADDR = (addr >> 19) & 0xff;
NFADDR = (addr >> 27) & 0x3;
NFCMD = NAND_CMD_READSTART;
#endif
NAND_DETECT_RB;
for(n=0; n<NAND_SECTOR_SIZE; n++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
size -= j;
} //else PrintChar('e');
baddr += (BYTESPERSPAGE*PAGESPERSBLOCK);
}
NAND_CHIP_DISABLE;
return 0;
}
|
本人修改改为如下编译后能正常使用:
#ifndef LARGEPAGE_FLASH
#define NAND_SECTOR_SIZE 512
#define PAGESPERBLOCK 32
#else
#define NAND_SECTOR_SIZE 2048
#define PAGESPERBLOCK 64
#endif
#define NAND_BLOCK_SIZE (NAND_SECTOR_SIZE*PAGESPERBLOCK)
#define NAND_BLOCK_MASK (NAND_BLOCK_SIZE - 1)
void PrintChar(char msg);
void PrintWord(unsigned int msg);
static int maf_id,dev_id;
/* low level nand read function */
int nand_block_checkbad_ll(unsigned long addr);
void PrintChar(char msg);
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int j, n;
unsigned long addr,baddr;
#ifdef CONFIG_DEBUG_LL
PrintWord(*((unsigned int *)"NFRD"));
#endif
if ((start_addr & NAND_BLOCK_MASK)/* || (size & NAND_BLOCK_MASK)*/) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
baddr=start_addr;
for( ;size>0; baddr+=NAND_BLOCK_SIZE) {
if (nand_block_checkbad_ll(baddr)){
#ifdef CONFIG_DEBUG_LL
PrintChar('e');
#endif
continue;
}
for (j=0;j<NAND_BLOCK_SIZE && j<size;j+=NAND_SECTOR_SIZE) {
/* READ0 */
NAND_CLEAR_RB;
NFCMD = NAND_CMD_READ0;
addr = baddr+j;
/* Write Address */
#ifndef LARGEPAGE_FLASH
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
#else
NFADDR = addr & 0xff;
NFADDR = (addr >> 8) & 0x07;
NFADDR = (addr >> 11) & 0xff;
NFADDR = (addr >> 19) & 0xff;
NFADDR = (addr >> 27) & 0x3;
NFCMD = NAND_CMD_READSTART;
#endif
NAND_DETECT_RB;
for(n=0; n<NAND_SECTOR_SIZE; n++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
size -= NAND_BLOCK_SIZE;
}
NAND_CHIP_DISABLE;
return 0;
}
|
本人将2k页面的支持加下了menuconfig脚本中,在Menuconfig->Main menu->Memory Technology Devices(MTD)->NAND Flash Device Drivers中选中Large Page Device Support即会开启2K页面NAND Flash支持,以上是本人升级Flash的最终成果,附上修改后的vivi源代码。
|
文件: | vivi2440_src.zip |
大小: | 836KB |
下载: | 下载 |
|
阅读(2333) | 评论(0) | 转发(0) |