SylixOS下基于NUC970的NAND驱动
開發(fā)環(huán)境
開發(fā)環(huán)境
宿主機(jī): Windows7 64bits 系統(tǒng)
開發(fā)板: 安米MDK972
軟件環(huán)境: RealEvo-IDE3.0
NAND Flash: S34ML02G100TF100
S34ML02G100TF100芯片參數(shù)
Density:2 Gbit
Input / Output Bus Width: 8-bits
Page Size:2112 (2048 + 64) bytes; 64 bytes is spare area
Block Size: 64 Pages;128k + 4k bytes
Plane Size: 1024 Blocks per Plane;128M + 4M bytes
Device Size: 2 Planes per Device or 256 Mbyte
NAND控制器結(jié)構(gòu)
NUC970的NAND控制器包含在FMI中。FMI分為DMA單元和FMI單元。對(duì)于NAND,支持單一DMA通道和硬件ECC,如圖 2-1所示。
圖 2-1 ? NUC970 NAND控制器
?
技術(shù)實(shí)現(xiàn)
驅(qū)動(dòng)框架
SylixOS中NAND Flsh的驅(qū)動(dòng)框架如圖 3-1所示。NAND通用驅(qū)動(dòng)主要在fs/mtd/nand/nand_base.c中,該文件包含了NAND的通用操作。驅(qū)動(dòng)工程師需要在NAND通用驅(qū)動(dòng)的基礎(chǔ)上實(shí)現(xiàn)與硬件相關(guān)的驅(qū)動(dòng)層的結(jié)構(gòu)體(nand_chip),該結(jié)構(gòu)體包含了對(duì)具體硬件相關(guān)的控制和操作函數(shù),以及相關(guān)硬件參數(shù)和配置信息。MTD層與文件系統(tǒng),SylixOS已經(jīng)完全實(shí)現(xiàn),不需要驅(qū)動(dòng)工程師實(shí)現(xiàn)。
圖 3-1 ? NAND驅(qū)動(dòng)框架
框架實(shí)現(xiàn)
NAND驅(qū)動(dòng)需要完成NAND控制器、ECC的配置以及NAND的相關(guān)操作函數(shù)及文件系統(tǒng)掛載,如果使用硬件ECC一般自己定義OOB布局。NUC970驅(qū)動(dòng)實(shí)現(xiàn)的操作如程序清單 3-1所示。
程序清單 3-1 ? NAND實(shí)現(xiàn)框架
????nandchipNand->cmd_ctrl????????=?hwControl;nandchipNand->cmdfunc?????????=?nandCommand;nandchipNand->dev_ready???????=?devReady;nandchipNand->select_chip?????=?chipSelect;nandchipNand->read_byte???????=?nandReadByte;nandchipNand->write_buf???????=?nandWriteBuf;nandchipNand->read_buf????????=?nandReadBuf;nandchipNand->chip_delay??????=?50;nandchipNand->ecc.mode????????=?NAND_ECC_HW_OOB_FIRST;nandchipNand->ecc.hwctl???????=?nandEnableHwEcc;nandchipNand->ecc.calculate???=?nandCalculateEcc;nandchipNand->ecc.correct?????=?nandCorrectData;nandchipNand->ecc.write_page??=?nandWritePageHwEcc;nandchipNand->ecc.read_page???=?nandReadPageHwEccOobFirst;nandchipNand->ecc.read_oob????=?nandReadoobHwEcc; nandchipNand->ecc.layout??????=?&__Gpnuc970nandoob;?
控制器初始化
控制器初始化主要實(shí)現(xiàn)了模塊時(shí)鐘使能、管腳復(fù)用、時(shí)序設(shè)置、片選、解除寫保護(hù)、頁(yè)大小、軟件復(fù)位等操作。
ECC配置
ECC配置主要設(shè)置冗余區(qū)大小,保護(hù)前3字節(jié),自動(dòng)寫校驗(yàn)值到NAND,設(shè)置算法等級(jí),ECC使能等操作。
函數(shù)cmd_ctrl
該函數(shù)主要實(shí)現(xiàn)對(duì)ALE/CLE/nCE的控制,同時(shí)用來(lái)寫命令和地址。
程序清單?3-2 ?命令控制函數(shù)
?
static?VOID?hwControl?(struct?mtd_info??*pMtd,?INT??iCmd,?UINT??uiCtrl) {struct?nand_chip?*pChip?=?pMtd->priv;if?(uiCtrl?&?NAND_CTRL_CHANGE)?{ULONG?IO_ADDR_W?=?(ULONG)REG_NANDDATA;if?((uiCtrl?&?NAND_CLE))?{IO_ADDR_W?=?REG_NANDCMD;}if?((uiCtrl?&?NAND_ALE))?{IO_ADDR_W?=?REG_NANDADDR;}pChip->IO_ADDR_W?=?(VOID?*)IO_ADDR_W;}if?(iCmd?!=?NAND_CMD_NONE)?{writeb(iCmd,?pChip->IO_ADDR_W);} }函數(shù)cmdfunc
該函數(shù)主要實(shí)現(xiàn)向芯片中寫命令的功能,在系統(tǒng)提供的默認(rèn)函數(shù)中通過調(diào)用cmd_ctrl函數(shù)來(lái)實(shí)現(xiàn)具體寫操作。由于NUC970的控制器需在最后一個(gè)地址周期手動(dòng)設(shè)置EOA位,無(wú)法使用默認(rèn)函數(shù),差異代碼如程序清單 3-3所示:
程序清單 3-3 ??命令功能函數(shù)差異代碼
writel((iColumn?>>?BUS_WIDTH)?|?NANDADDR_EOA,?REG_NANDADDR);?
函數(shù)dev_ready
該函數(shù)主要用來(lái)獲得設(shè)備ready/busy引腳狀態(tài)。如果該函數(shù)指針設(shè)置為NULL無(wú)法獲得ready/busy引腳狀態(tài),則ready/busy信息需要通過讀取NAND芯片的狀態(tài)寄存器。代碼實(shí)現(xiàn)如程序清單 3-4所示。
程序清單 3-4 ?獲得NAND狀態(tài)
????return?((readl(REG_NANDINTSTS)?&?NANDINTSTS_RB0_Status)???1?:?0);?
函數(shù)read_byte
該函數(shù)功能為從NAND芯片讀取一個(gè)字節(jié),代碼如程序清單 3-5所示。
程序清單 3-5 ?從NAND讀一個(gè)字節(jié)
?
????return?((UCHAR)readl(REG_NANDDATA));?
函數(shù)write_buf
該函數(shù)功能為從一個(gè)緩沖區(qū)寫數(shù)數(shù)據(jù)到NAND芯片。代碼實(shí)現(xiàn)如程序清單 3-6。
程序清單 3-6 ?寫緩沖區(qū)數(shù)據(jù)到NAND
?
????for?(i?=?0;?i?<?iLen;?i++)?{writel(pucbuf[i],?REG_NANDDATA);}?
函數(shù)read_buf
該函數(shù)功能為從NAND芯片讀數(shù)據(jù)到一個(gè)緩沖區(qū)。代碼實(shí)現(xiàn)如程序清單 3-7所示。
程序清單 3-7 ?讀數(shù)據(jù)到緩沖區(qū)
?
????for?(i?=?0;?i?<?iLen;?i++)?{writel(pucbuf[i],?REG_NANDDATA);}?
函數(shù)ecc.hwctl
該函數(shù)用于控制硬件ECC發(fā)生器,只有在使用硬件ECC時(shí)實(shí)現(xiàn)。本例的硬件校驗(yàn)在傳輸中實(shí)現(xiàn),因此該函數(shù)為空實(shí)現(xiàn)。
函數(shù)ecc.calculate
該函數(shù)用于ECC計(jì)算,或從ECC硬件中讀回。本例的硬件校驗(yàn)在傳輸中實(shí)現(xiàn),因此該函數(shù)為空實(shí)現(xiàn)。
函數(shù)ecc.correct
該函數(shù)用于ECC校正。本例的硬件校驗(yàn)在傳輸中實(shí)現(xiàn),因此該函數(shù)為空實(shí)現(xiàn)。
函數(shù)ecc.write_page
該函數(shù)主要實(shí)現(xiàn)帶ECC的寫一頁(yè)數(shù)據(jù)到NAND芯片。在傳輸?shù)倪^程中,ECC電路會(huì)自動(dòng)計(jì)算ECC校驗(yàn)值,并存儲(chǔ)到控制器分配的寄存器組中。完成傳輸后寄存器組中的OOB數(shù)據(jù)會(huì)根據(jù)設(shè)置自動(dòng)寫進(jìn)NAND芯片。實(shí)現(xiàn)流程如程序清單 3-8所示。
程序清單 3-8 ?帶硬件ECC的寫頁(yè)
static?INT?nandWritePageHwEcc?(struct?mtd_info???*pMtd,struct?nand_chip??*pChip,const?UCHAR???????*pucBuf,INT????????????????iOobRequired) {UCHAR??????????*pucEccCalc???=?pChip->buffers->ecccalc;UINT?????????????uiEccBytes??=?pChip->ecc.layout->eccbytes;register?CHAR?????*pcPtr?????=?(CHAR?*)REG_NANDRA0;memset((VOID?*)pcPtr,?0xFF,?pMtd->oobsize);memcpy((VOID?*)pcPtr,?(VOID?*)pChip->oob_poi,??pMtd->oobsize?-?pChip->ecc.total);nandDmaTransfer(pMtd,?pucBuf,?pMtd->writesize?,?0x1);/**??Copy?parity?code?in?SMRA?to?calc*/memcpy((VOID?*)pucEccCalc,(VOID?*)(REG_NANDRA0?+?(pMtd->oobsize?-?pChip->ecc.total)),pChip->ecc.total);/**??Copy?parity?code?in?calc?to?oob_poi*/memcpy((VOID?*)(pChip->oob_poi?+?uiEccBytes),(VOID?*)pucEccCalc,pChip->ecc.total);return?0; }?
函數(shù)ecc.read_page
該函數(shù)主要實(shí)現(xiàn)帶ECC校驗(yàn)的從NAND芯片讀出一頁(yè)數(shù)據(jù)。本例為硬件ECC,需要先讀出OOB區(qū)數(shù)據(jù)到控制器分配的寄存器組中。在數(shù)據(jù)傳輸?shù)倪^程中,ECC電路會(huì)計(jì)算ECC校驗(yàn)值,并與寄存器組中的值比較,檢查是否產(chǎn)生錯(cuò)誤,以及定位和計(jì)算校錯(cuò)值。若產(chǎn)生錯(cuò)誤,程序需要根據(jù)錯(cuò)誤位置和錯(cuò)誤值進(jìn)行校錯(cuò)。具體流程如程序清單 3-9所示:
程序清單 3-9 ?帶ECC的讀頁(yè)
?
static?INT?nandReadPageHwEccOobFirst?(struct?mtd_info???*pMtd,struct?nand_chip??*pChip,UCHAR?????????????*ucBuf,INT????????????????iOobRequired,INT????????????????iPage) {INT??????iEccSize?=?pChip->ecc.size;CHAR????*pcPtr????=?(CHAR?*)REG_NANDRA0;/**??At?first,?read?the?OOB?area*/nandCommand(pMtd,?NAND_CMD_READOOB,?0,?iPage);nandReadBuf(pMtd,?pChip->oob_poi,?pMtd->oobsize);/**??Second,?copy?OOB?data?to?SMRA?for?page?read*/memcpy((VOID?*)pcPtr,?(VOID?*)pChip->oob_poi,?pMtd->oobsize);/**??Third,?read?data?from?nand*/nandCommand(pMtd,?NAND_CMD_READ0,?0,?iPage);nandDmaTransfer(pMtd,?ucBuf,?iEccSize,?0x0);/**??Fouth,?restore?OOB?data?from?SMRA*/memcpy((VOID?*)pChip->oob_poi,?(VOID?*)pcPtr,?pMtd->oobsize);return?0; }?
函數(shù)ecc.read_oob
該函數(shù)主要實(shí)現(xiàn)從芯片中讀取OOB數(shù)據(jù)。實(shí)現(xiàn)流程如程序清單 3-10所示。
程序清單 3-10 ?帶硬件ECC的讀OOB區(qū)數(shù)據(jù)
?
static?INT?nandReadoobHwEcc(struct?mtd_info??*pMtd,?struct?nand_chip??*pChip,?INT??iPage) {CHAR?*cPtr?=?(char?*)REG_NANDRA0;/**??At?first,?read?the?OOB?area*/nandCommand(pMtd,?NAND_CMD_READOOB,?0,?iPage);nandReadBuf(pMtd,?pChip->oob_poi,?pMtd->oobsize);/**??Second,?copy?OOB?data?to?SMRA?for?page?read*/memcpy?((VOID?*)cPtr,?(VOID?*)pChip->oob_poi,?pMtd->oobsize);return?0; }?
ecc.layout
nand_ecc為ECC布局控制結(jié)構(gòu)體。通過該結(jié)構(gòu)體配置OOB區(qū)中ECC的位數(shù)和位置,可用位數(shù)和空閑位數(shù)。本例通過調(diào)用程序清單 3-11代碼實(shí)現(xiàn)OOB區(qū)的布局控制。
程序清單 3-11 ? OOB區(qū)布局
?
static?VOID?oobTableLayout?(?struct?nand_ecclayout??*pNandOOBTbl,?INT??iOobSize?,?INT??iEccBytes) {pNandOOBTbl->eccbytes?????=?iEccBytes;pNandOOBTbl->oobavail?????=?iOobSize?-?DEF_RESERVER_OOB_SIZE_FOR_MARKER?-?iEccBytes?;pNandOOBTbl->oobfree[0].offset?=?DEF_RESERVER_OOB_SIZE_FOR_MARKER;?????/*??Bad?block?marker?size????*/pNandOOBTbl->oobfree[0].length?=?iOobSize?-?iEccBytes?-?pNandOOBTbl->oobfree[0].offset?; }?
文件系統(tǒng)掛載
在SylixOS下NAND Flash通常掛載YAFFS文件系統(tǒng),并分為n0和n1分區(qū),其中n0分區(qū)用作啟動(dòng)分區(qū),n1作為應(yīng)用分區(qū)。掛載流程如程序清單 3-12所示。
程序清單 3-12 ?文件系統(tǒng)掛掛載
?
????yaffs_mtd_drv_install(&__GyaffsdevBootDev);yaffs_mtd_drv_install(&__GyaffsdevCommDev);yaffs_add_device(&__GyaffsdevBootDev);??????????????????????????????/*?add?to?yaffs?device?table????*/yaffs_add_device(&__GyaffsdevCommDev);??????????????????????????????/*?add?to?yaffs?device?table????*/yaffs_mount(cBootDevName);yaffs_mount(cCommDevName);?
參考資料
無(wú)。
轉(zhuǎn)載于:https://blog.51cto.com/12557713/1898029
總結(jié)
以上是生活随笔為你收集整理的SylixOS下基于NUC970的NAND驱动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML5能为我们带来什么?(一)
- 下一篇: webpack 与 热编译webpack