分类:
2012-09-23 18:55:07
由于NandFlash硬件升级比较快,公司去年一直在使用三星的K9GAG08U0D,现在MLC NandFlash 升级到了第二代,K9GAG08U0D 很快就会处在停产的状态,未雨绸缪,公司选型了K9GAG08U0E 来替代原有的NandFlash芯片。起初。本以为把新Nandflash ID信息增加到Uboot 和 Linux内核的NandFlash ID 列表文件中即可,也就是Uboot 和Linux源码中的nand_ids.c 文件中,但是仔细看了 K9GAG08U0E 的DataSheet,发现自己的想法错了。
下面记录了NandFlash更换时面临的几个问题,及解决方法:
第一个问题:ID 冲突
K9GAG08U0E 的 Product ID与 K9GAG08U0D 的Product ID 是相同的,都是 0xd5,而在Uboot 代码和Linux内核代码中,是根据ID信息来获取或者计算NandFlash的页大小和块大小这些关键信息的。
现在这两款的 Flash ID相同,而Page,OOB ,Block大小都是不同的。 K9GAG08U0D Page,OOB,Block 关键参数:
而K9GAG08U0E 的 Page,OOB,Block 关键参数:
可见他们是不同的,U0E 每页大小是U0D的两倍。
针对相同ID的两款不同Flash是怎样区分的呢?仔细看DataSheet,发现了可以快速区分两种设备的方法:
U0D Page=4K,U0D Page=8K,我们只需判断Read第四个字节的第0位和第1位即可。
下面列出关键代码段:
//这里必须有下面两行代码,因为U0E的DataSheet要求系统上电后第一条指令必须是NAND_CMD_RESET,而U0D没有这要求,如果不发送这条指令是无法读取到NandFlash的任何信息的,因为这个问题查找了很长时间,在这里提醒给大家。
// K9GAG08U0E must add below codes
{
s3c_nand_hwcontrol(0, NAND_CMD_RESET, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
}
s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
tmp = readb(nand->IO_ADDR_R); /* Maf. ID */
// printf("Manufactor ID:%x\n",tmp);
tmp = dev_id = readb(nand->IO_ADDR_R); /* Device ID */
//printf("dev_id ID:%x \n",dev_id);
for (i = 0; nand_flash_ids[i].name != NULL; i++)
{
if (tmp == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
nand->cellinfo = readb(nand->IO_ADDR_R);/* 3rd byte */
tmp = readb(nand->IO_ADDR_R);/* 4th byte */
int childType=tmp & 0x03; //Page size
// printf("dev_id=%x,childType=%x \n",dev_id,childType);
if(dev_id == 0xd5 && childType==0x01) //U0D
{
}else if(dev_id == 0xd5 && childType==0x02) //U0E
{
}
这样针对不同的NandFlash做不同的初始化了,以上代码来自uboot1.1.6/cpu/s3c64xx/nand.c 文件中的void board_nand_init(struct nand_chip *nand) 函数。