溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SylixOS下基于NUC970的NAND驅(qū)動

發(fā)布時間:2020-04-05 08:03:16 來源:網(wǎng)絡(luò) 閱讀:975 作者:huikai309 欄目:系統(tǒng)運維

開發(fā)環(huán)境

  1. 開發(fā)環(huán)境

    宿主機(jī): Windows7 64bits 系統(tǒng)

    開發(fā)板: 安米MDK972

    軟件環(huán)境: RealEvo-IDE3.0

    NAND Flash: S34ML02G100TF100

  2. 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單元。對于NAND,支持單一DMA通道和硬件ECC,如圖 2-1所示。

SylixOS下基于NUC970的NAND驅(qū)動

2-1   NUC970 NAND控制器

 

技術(shù)實現(xiàn)

  1. 驅(qū)動框架

    SylixOS中NAND Flsh的驅(qū)動框架如圖 3-1所示。NAND通用驅(qū)動主要在fs/mtd/nand/nand_base.c中,該文件包含了NAND的通用操作。驅(qū)動工程師需要在NAND通用驅(qū)動的基礎(chǔ)上實現(xiàn)與硬件相關(guān)的驅(qū)動層的結(jié)構(gòu)體(nand_chip),該結(jié)構(gòu)體包含了對具體硬件相關(guān)的控制和操作函數(shù),以及相關(guān)硬件參數(shù)和配置信息。MTD層與文件系統(tǒng),SylixOS已經(jīng)完全實現(xiàn),不需要驅(qū)動工程師實現(xiàn)。

    SylixOS下基于NUC970的NAND驅(qū)動

    3-1   NAND驅(qū)動框架

  2. 框架實現(xiàn)

    NAND驅(qū)動需要完成NAND控制器、ECC的配置以及NAND的相關(guān)操作函數(shù)及文件系統(tǒng)掛載,如果使用硬件ECC一般自己定義OOB布局。NUC970驅(qū)動實現(xiàn)的操作如程序清單 3-1所示。

    程序清單 3-1   NAND實現(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;

     

  3. 控制器初始化

    控制器初始化主要實現(xiàn)了模塊時鐘使能、管腳復(fù)用、時序設(shè)置、片選、解除寫保護(hù)、頁大小、軟件復(fù)位等操作。

  4. ECC配置

    ECC配置主要設(shè)置冗余區(qū)大小,保護(hù)前3字節(jié),自動寫校驗值到NAND,設(shè)置算法等級,ECC使能等操作。

  5. 函數(shù)cmd_ctrl

    該函數(shù)主要實現(xiàn)對ALE/CLE/nCE的控制,同時用來寫命令和地址。

    程序清單 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);
        }
    }
  6. 函數(shù)cmdfunc

    該函數(shù)主要實現(xiàn)向芯片中寫命令的功能,在系統(tǒng)提供的默認(rèn)函數(shù)中通過調(diào)用cmd_ctrl函數(shù)來實現(xiàn)具體寫操作。由于NUC970的控制器需在最后一個地址周期手動設(shè)置EOA位,無法使用默認(rèn)函數(shù),差異代碼如程序清單 3-3所示:

    程序清單 3-3   命令功能函數(shù)差異代碼

    writel((iColumn >> BUS_WIDTH) | NANDADDR_EOA, REG_NANDADDR);

     

  7. 函數(shù)dev_ready

    該函數(shù)主要用來獲得設(shè)備ready/busy引腳狀態(tài)。如果該函數(shù)指針設(shè)置為NULL無法獲得ready/busy引腳狀態(tài),則ready/busy信息需要通過讀取NAND芯片的狀態(tài)寄存器。代碼實現(xiàn)如程序清單 3-4所示。

    程序清單 3-4  獲得NAND狀態(tài)

        return ((readl(REG_NANDINTSTS) & NANDINTSTS_RB0_Status) ? 1 : 0);

     

  8. 函數(shù)read_byte

    該函數(shù)功能為從NAND芯片讀取一個字節(jié),代碼如程序清單 3-5所示。

    程序清單 3-5  NAND讀一個字節(jié)

     

        return ((UCHAR)readl(REG_NANDDATA));

     

  9. 函數(shù)write_buf

    該函數(shù)功能為從一個緩沖區(qū)寫數(shù)數(shù)據(jù)到NAND芯片。代碼實現(xiàn)如程序清單 3-6。

    程序清單 3-6  寫緩沖區(qū)數(shù)據(jù)到NAND

     

        for (i = 0; i < iLen; i++) {
            writel(pucbuf[i], REG_NANDDATA);
        }

     

  10. 函數(shù)read_buf

    該函數(shù)功能為從NAND芯片讀數(shù)據(jù)到一個緩沖區(qū)。代碼實現(xiàn)如程序清單 3-7所示。

    程序清單 3-7  讀數(shù)據(jù)到緩沖區(qū)

     

        for (i = 0; i < iLen; i++) {
            writel(pucbuf[i], REG_NANDDATA);
        }

     

  11. 函數(shù)ecc.hwctl

    該函數(shù)用于控制硬件ECC發(fā)生器,只有在使用硬件ECC時實現(xiàn)。本例的硬件校驗在傳輸中實現(xiàn),因此該函數(shù)為空實現(xiàn)。

  12. 函數(shù)ecc.calculate

    該函數(shù)用于ECC計算,或從ECC硬件中讀回。本例的硬件校驗在傳輸中實現(xiàn),因此該函數(shù)為空實現(xiàn)。

  13. 函數(shù)ecc.correct

    該函數(shù)用于ECC校正。本例的硬件校驗在傳輸中實現(xiàn),因此該函數(shù)為空實現(xiàn)。

  14. 函數(shù)ecc.write_page

    該函數(shù)主要實現(xiàn)帶ECC的寫一頁數(shù)據(jù)到NAND芯片。在傳輸?shù)倪^程中,ECC電路會自動計算ECC校驗值,并存儲到控制器分配的寄存器組中。完成傳輸后寄存器組中的OOB數(shù)據(jù)會根據(jù)設(shè)置自動寫進(jìn)NAND芯片。實現(xiàn)流程如程序清單 3-8所示。

    程序清單 3-8  帶硬件ECC的寫頁

    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;
    }


     

  15. 函數(shù)ecc.read_page

    該函數(shù)主要實現(xiàn)帶ECC校驗的從NAND芯片讀出一頁數(shù)據(jù)。本例為硬件ECC,需要先讀出OOB區(qū)數(shù)據(jù)到控制器分配的寄存器組中。在數(shù)據(jù)傳輸?shù)倪^程中,ECC電路會計算ECC校驗值,并與寄存器組中的值比較,檢查是否產(chǎn)生錯誤,以及定位和計算校錯值。若產(chǎn)生錯誤,程序需要根據(jù)錯誤位置和錯誤值進(jìn)行校錯。具體流程如程序清單 3-9所示:

    程序清單 3-9  ECC的讀頁

     

    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;
    }

     

  16. 函數(shù)ecc.read_oob

    該函數(shù)主要實現(xiàn)從芯片中讀取OOB數(shù)據(jù)。實現(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;
    }

     

  17. ecc.layout

    nand_ecc為ECC布局控制結(jié)構(gòu)體。通過該結(jié)構(gòu)體配置OOB區(qū)中ECC的位數(shù)和位置,可用位數(shù)和空閑位數(shù)。本例通過調(diào)用程序清單 3-11代碼實現(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 ;
    }

     

  18. 文件系統(tǒng)掛載

    在SylixOS下NAND Flash通常掛載YAFFS文件系統(tǒng),并分為n0和n1分區(qū),其中n0分區(qū)用作啟動分區(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);

     

參考資料

無。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI