nandflash特點:
- nand存在位反轉的現象,是以需要ecc校驗資料,ecc校驗可以矯正一位的位反轉,發現兩位的位反轉;
- nand存在壞塊的問題,所謂壞塊,就是不能擦除的塊,nandflash隻能從1寫為0;而不能從0寫為1,也就是write時,隻能将某一位拉低;而擦除操作是将0拉高位1。擦除是按塊擦的,寫的話按頁寫。寫的話按頁寫是為了提高效率,而擦除隻能按塊擦除。
- nandflash的接口有并口和spi接口的。
硬體結構
原理圖
并口的nandflash,8bit flash,位址和資料線共用
ALE和CLE用于位址和資料選擇。
内部結構
頁結構
每一頁2048 data+64OOB;OOB(out of band);OOB主要有2byte壞快辨別 + ECC資料;
壞塊辨別0xff為好塊,其他為壞。壞塊辨別每一塊的第一頁的OOB區内。
以上頁結構資訊,不同的晶片廠商結構也不一樣。
nandflash指令集
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_PARAM 0xec
#define NAND_CMD_GET_FEATURES 0xee
#define NAND_CMD_SET_FEATURES 0xef
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
#define NAND_CMD_NONE -1
mtd nandflash驅動
mtd架構分層:
裝置層: mtdchar.c/mtdblock.c; 字元裝置和塊裝置接口。
原始裝置層 mtdcore.c 提供mtd_info;mtd_partion;mtd_part結構。
硬體驅動層 /mtd/nand/下
nand_base.c nand通用接口;
分rawnand;onenand,spinand;
rawnand: 位址資料總線為并口。
spinand:通過spi總線控制,相當與rawnand封裝成了spi接口。多了一個spi解釋單元。
onenand:可以了解為nor+nand。
mtd架構能做什麼不能做什麼?
-
nand flash有壞塊,mtd驅動架構能幫我們跳壞塊嗎?
答:不能,mtd隻提供讀寫page接口,和ioctl接口來測試該塊是否為壞塊,但是不會在讀寫的時候幫我們自動跳過壞塊,跳壞塊操作需要我們應用來自己實作。
-
nandflash會存在位反轉現象,mtd驅動架構會幫我們做ecc校驗嗎? 糾正一位的bitflip,發現2bit的bitflip?
答:這個mtd驅動架構會幫做,但是ecc校驗可選軟體ecc和硬體ecc,軟體ecc算法mtd架構提供,硬體ecc則是硬體結構提供,讀資料的時候會校驗。
-
nandflash擦除是按塊擦除的,寫是按頁寫的,如果我們要寫一個塊中的某一頁,需要将整個塊讀出來然後,修改然後擦除寫入。即read-update-erase-write;這個操作mtd會幫我們做嗎?
答:不會。mtd隻提供頁寫入接口,這一系列操作需要使用者自己做。至于提高寫入速率的操作,也需要使用者自己實作。
rawnand驅動字元裝置接口
字元裝置寫流程圖:
1. 寫資料不跳壞塊
2. oob中ecc資料可以是
1> 原始資料中已經帶有的
2> 軟體算法生成的 3中算法;
3> 硬體實作ecc算法;需要驅動實作ecc…
3. 不提供block寫buffer;即read-update-erase-write流程。
讀資料流
1.同樣不跳壞塊
2.ecc校驗 nand_chip.ecc.correct
見代碼硬體ecc分支nand_read_page_hwecc:
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->ecc.code_buf;
unsigned int max_bitflips = 0;
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
eccsteps = chip->ecc.steps;
p = buf;
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
stat = nand_check_erased_ecc_chunk(p, eccsize,
&ecc_code[i], eccbytes,
NULL, 0,
chip->ecc.strength);
}
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
壞快表BBT
有的廠商将壞塊表存放在flash第一塊的第一頁中,因為廠商出廠時第一頁會確定為好塊的。但是如果flash用來存放代碼,則不能第一頁不能用來存放壞快表。有的廠商将壞塊表放在最後一塊,但是要確定最後一塊為好塊。
mtdchar iotcl判斷該塊是否為壞塊。
case MEMGETBADBLOCK:
{
loff_t offs;
if (copy_from_user(&offs, argp, sizeof(loff_t)))
return -EFAULT;
return mtd_block_isbad(mtd, offs);
break;
}
調用鍊
如果記憶體中沒有bbt(chip->bbt);則去讀oob區域;
如果有bbt,則從bbt[]中讀取資料;
标記壞塊時,标記bbt并更新oob區域。
nor flash
cfi接口;jedec(老的接口)