U-boot-2012-10的NAND驱动默认是采用了4位ECC 纠正,由于S3C6410对MLC nand也支持8位ECC,所以本次实验将移植8位ECC到OK6410板子上。
首先解释前面所说的OOB size=128的问题:
这块开发板使用的NAND型号是K9GAG08U0D,查看手册可以知道OOB SIZE是218字节。但我们前面移植时在配置NAND的信息后打印出来的OOB size =128。这显然不对,通过查看代码我们知道在nand_get_flash_type(drivers/mtd/nand/nand_base.c)函数中有这一段:
if (!type->pagesize) {
..........
extid >>= 2;//zxd extid=0x29
/* Calc oobsize */
switch (extid & 0x03) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
default:
mtd->oobsize = 436;
break;
}
.........
刚开始我们采用uboot2012.10原来的NAND配置信息时,有提示oob size是218的,但我们配置信息后就没有了,显然要么是配置不对,要么是程序没有走到这段来,再看进入这段程序的条件是if (!type->pagesize) 也就是说当type->pagesize=0时才进入这段程序。type首先是指到nand_flash_ids这个结构体上,然后再通过
for (; type->name != NULL; type++)
if (*dev_id == type->id)
break;
找到对于的NAND信息。记得我们前面有对nand_flash_ids这个结构体做了修改:
##{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},##改为
{"NAND 2GiB 3,3V 8-bit", 0xD5, 4096, 2048, 512*1024, LP_OPTIONS},
那么就是说
type->pagesize=4096.当然就不符合if (!type->pagesize)这个条件了。把它改回来后打印:
SMDK6410 # nand info
Device 0: nand0, sector size 512 KiB
Page size 4096 b
OOB size 218 b
Erase size 524288 b
SMDK6410 #
可以看到已经对了。
OK,现在来讲一下8bit ECC的移植过程:
1.smdk6410.h(include/configs)增加
#define CONFIG_NAND_BL1_8BIT_ECC
再修改:
/* Size of the block protected by one OOB (Spare Area in Samsung terminology) */
#define CONFIG_SYS_NAND_ECCSIZE 512
/* Number of ECC bytes per OOB - S3C6400 calculates 4 bytes ECC in 1-bit mode */
#ifdef CONFIG_NAND_BL1_8BIT_ECC
#define CONFIG_SYS_NAND_ECCBYTES 13
#else
#define CONFIG_SYS_NAND_ECCBYTES 4
#endif
2.s3c64xx.c(drivers/mtd/nand/)增加这几个函数:
#if defined(CONFIG_NAND_BL1_8BIT_ECC) && (defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430))
/***************************************************************
* jsgood: Temporary 8 Bit H/W ECC supports for BL1 (6410/6430 only)
***************************************************************/
int cur_ecc_mode=0;
/*
* Function for checking ECCEncDone in NFSTAT
* Written by jsgood
*/
static void s3c_nand_wait_enc(void)
{
while (!(readl(NFSTAT) & NFSTAT_ECCENCDONE)) {}
}
/*
* Function for checking ECCDecDone in NFSTAT
* Written by jsgood
*/
static void s3c_nand_wait_dec(void)
{
while (!(readl(NFSTAT) & NFSTAT_ECCDECDONE)) {}
}
static void s3c_nand_wait_ecc_busy_8bit(void)
{
while (readl(NF8ECCERR0) & NFESTAT0_ECCBUSY) {}
}
void s3c_nand_enable_hwecc_8bit(struct mtd_info *mtd, int mode)
{
u_long nfcont, nfconf;
cur_ecc_mode = mode;
/* 8 bit selection */
nfconf = readl(NFCONF);
nfconf &= ~(0x3 << 23);
nfconf |= (0x1 << 2