星期六, 5月 21, 2011

Embedded System - Linux 如何新增 Nand Flash Notes

對於新加入的 flash, 參數修改可以在其相關 architecture 的 code 裡找到, 以 pxa3xx 系列為例子, 可以在 drivers/mtd/nand/pxa3xx_nand.c 裡面找到.

/* kernel 2.6.21 */

kernel 2.6.21 的 pxa3xx_nand.c 程式碼跟 WinCE 在結構上來說是大同小異, 值得關注的就是 dfc_flash_info 這個結構, 大部份的 flash 資訊都在這裡:

struct dfc_flash_info {
    struct dfc_flash_timing timing; /* NAND Flash timing */

    int  enable_arbiter;/* Data flash bus arbiter enable (ND_ARB_EN) */
    uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
    uint32_t row_addr_start;/* Row address start position (RA_START) */
    uint32_t read_id_bytes; /* returned ID bytes(RD_ID_CNT) */
    uint32_t dfc_mode; /* NAND, CARBONDALE, PIXLEY... (ND_MODE) */
    uint32_t ncsx;  /* Chip select don't care bit (NCSX) */
    uint32_t page_size; /* Page size in bytes (PAGE_SZ) */
    uint32_t oob_size; /* OOB size */
    uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */
    uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */
    uint32_t num_blocks; /* Number of physical blocks in Flash */
    uint32_t chip_id;
    uint32_t read_prog_cycles; /* Read Program address cycles */

    /* command codes */
    uint32_t read1;  /* Read */
    uint32_t read2;  /* unused, DFC don't support yet */
    uint32_t program; /* two cycle command */
    uint32_t read_status;
    uint32_t read_id;
    uint32_t erase;  /* two cycle command */
    uint32_t reset;
    uint32_t lock;  /* lock whole flash */
    uint32_t unlock; /* two cycle command, supporting partial unlock */
    uint32_t lock_status; /* read block lock status */

    /* addr2ndcb1 - encode address cycles into register NDCB1 */
    /* ndbbr2addr - convert register NDBBR to bad block address */
    int (*addr2ndcb1)(uint16_t cmd, uint32_t addr, uint32_t *p);
    int (*ndbbr2addr)(uint16_t cmd, uint32_t ndbbr,uint32_t *p);
};

大部份的東西對應 datasheet 都可以知道, 比較特別的名詞是 OOB (Out of Band), 這東西其實就是 datasheet 上的 spare area.
除此之外, 還有兩個 pointer to function, 這兩個 function 主要是用來做讀寫時位址換算, 因為 nand flash write 時是 by page, 而 erase 時是 by block, 所以在讀寫位置要特別處理.

/* kernel 2.6.36 */

kernel 2.6.36 值得注意的是 pxa3xx_nand_flash 這個結構如下:

struct pxa3xx_nand_flash {
    const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
    const struct pxa3xx_nand_cmdset *cmdset;

    uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
    uint32_t page_size; /* Page size in bytes (PAGE_SZ) */
    uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */
    uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */
    uint32_t num_blocks; /* Number of physical blocks in Flash */
    uint32_t chip_id;
};

可以看到裡面包含了 chip_id, page_size 等相關資訊, 以及 timing 跟 command set 這兩個結構:

struct pxa3xx_nand_timing {
    unsigned int tCH;  /* Enable signal hold time */
    unsigned int tCS;  /* Enable signal setup time */
    unsigned int tWH;  /* ND_nWE high duration */
    unsigned int tWP;  /* ND_nWE pulse time */
    unsigned int tRH;  /* ND_nRE high duration */
    unsigned int tRP;  /* ND_nRE pulse width */
    unsigned int tR;   /* ND_nWE high to ND_nRE low for read */
    unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */
    unsigned int tAR;  /* ND_ALE low to ND_nRE low delay */
};

timing 的部份, 請參考 datasheet 裡面有詳細的解說, 簡單來說就是在定義讀取跟寫入資料時, 哪幾條線要 pull high 幾個 clock 之類, 而這些 timing 每片 flash 都不盡相同.

struct pxa3xx_nand_cmdset {
    uint16_t read1;
    uint16_t read2;
    uint16_t program;
    uint16_t read_status;
    uint16_t read_id;
    uint16_t erase;
    uint16_t reset;
    uint16_t lock;
    uint16_t unlock;
    uint16_t lock_status;
};

再來就是 command set, 一般來說 nor flash 接法與 DRAM 一樣, 讀寫方式也類似, 最多要注意的就是 data bus 幾條跟 block 是由大到小或由小到大而已, 而 nand flash 都是用 command 來做資料傳輸的方式, 目前看得到的 nand flash, page size 基本上只有兩種: 512 跟 2048, 以後會不會有新的還不知道, 而這兩者 command set 大部份幾乎都一樣, 主要差別在 small page 跟 large page 的 read 會有點不同, 只要依照 datasheet 把正確的數值加上去就可以了.

要參考的函式:

dfc_init->dfc_get_flash_info

要修改的 struct:
enum {
 DFC_FLASH_NULL = 0 ,
 DFC_FLASH_Samsung_512Mb_X_16 = 1,
 DFC_FLASH_Micron_1Gb_X_8 = 2,
 DFC_FLASH_Micron_1Gb_X_16 = 3,
 DFC_FLASH_STM_1Gb_X_16 = 4,
 DFC_FLASH_STM_2Gb_X_16 = 5,
 DFC_FLASH_STM_MCP_1Gb_X_16 = 6,
 DFC_FLASH_Toshiba2GbX16 = 7,
 DFC_FLASH_END,
};

static struct {
 int type;
 struct dfc_flash_info *flash_info;
} type_info[] = {
 { DFC_FLASH_Samsung_512Mb_X_16, &samsung512MbX16},
 { DFC_FLASH_Micron_1Gb_X_8, &micron1GbX8},
 { DFC_FLASH_Micron_1Gb_X_16, &micron1GbX16},
 { DFC_FLASH_STM_1Gb_X_16, &stm1GbX16},
 { DFC_FLASH_STM_2Gb_X_16, &stm2GbX16},
 { DFC_FLASH_STM_MCP_1Gb_X_16, &stm70nm1GbX16},
 { DFC_FLASH_Toshiba2GbX16, &toshiba2GbX16},
 { DFC_FLASH_NULL, NULL},
};

沒有留言: