u-boot中nand-flash代码流程介绍

loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
可以从mtd的结构体初始化关联出来,每一个mtd设备关联chip指针,最终调用flash硬件接口
mtd->read = nand_erase;  ->   nand_erase_nand(mtd, instr, 0); -> chip->erase_cmd(mtd, page & chip->pagemask);


#ifdef CONFIG_SPI_NAND_FLASH_INIT_FIRST
#if __DEVICE_USING_QIO
__SECTION_INIT_PHASE_DATA
spi_nand_cmd_info_t toshiba_x4_cmd_info = {
    .w_cmd = PROGRAM_LOAD_OP,
    .w_addr_io = SIO_WIDTH,
    .w_data_io = SIO_WIDTH,
    .r_cmd = FAST_READ_X4_OP,
    .r_addr_io = SIO_WIDTH,
    .r_data_io = QIO_WIDTH,
    .r_dummy_cycles  = 8,
};
#endif

#if defined(NSU_DRIVER_IN_ROM) || (defined(CONFIG_SPI_NAND_FLASH_INIT_FIRST) && defined(CONFIG_UNDER_UBOOT))
__SECTION_INIT_PHASE_DATA 
spi_nand_model_info_t toshiba_general_model = {
    ._pio_write = snaf_pio_write_data,
    ._pio_read = snaf_pio_read_data,
    ._page_read = snaf_page_read,
    ._page_write = snaf_page_write,
    ._page_read_ecc = snaf_page_read_with_ondie_ecc,
    ._page_write_ecc = snaf_page_write_with_ondie_ecc,
    ._block_erase = nsc_block_erase,
    ._wait_spi_nand_ready = nsc_wait_spi_nand_oip_ready,
};
#endif

__SECTION_INIT_PHASE_DATA
spi_nand_flash_info_t toshiba_chip_info[] = {
    {
        .man_id              = MID_TOSHIBA, 
        .dev_id              = DID_TC58CVG0S3HRAIG,
        ._num_block          = SNAF_MODEL_NUM_BLK_1024,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_USE_ODE,        
        #if __DEVICE_REASSIGN
            ._ecc_encode     = VZERO,
            ._ecc_decode     = VZERO,
            ._reset          = VZERO,
            ._cmd_info       = VZERO,
            ._model_info     = VZERO,
        #elif __DEVICE_USING_SIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_sio_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_DIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_x2_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_QIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &toshiba_x4_cmd_info,
            ._model_info     = &toshiba_general_model,
        #endif
    },
    {
        .man_id              = MID_TOSHIBA, 
        .dev_id              = DID_TC58CVG1S3HRAIG,
        ._num_block          = SNAF_MODEL_NUM_BLK_2048,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_USE_ODE,        
        #if __DEVICE_REASSIGN
            ._ecc_encode     = VZERO,
            ._ecc_decode     = VZERO,
            ._reset          = VZERO,
            ._cmd_info       = VZERO,
            ._model_info     = VZERO,
        #elif __DEVICE_USING_SIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_sio_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_DIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_x2_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_QIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &toshiba_x4_cmd_info,
            ._model_info     = &toshiba_general_model,
        #endif
    },
    {
        .man_id              = MID_KIOXIA,
        .dev_id              = DID_TC58CVG0S3HRAIJ,
        ._num_block          = SNAF_MODEL_NUM_BLK_1024,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_USE_ODE,
        #if __DEVICE_REASSIGN
            ._ecc_encode     = VZERO,
            ._ecc_decode     = VZERO,
            ._reset          = VZERO,
            ._cmd_info       = VZERO,
            ._model_info     = VZERO,
        #elif __DEVICE_USING_SIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_sio_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_DIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_x2_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_QIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &toshiba_x4_cmd_info,
            ._model_info     = &toshiba_general_model,
        #endif
    },
    {
        .man_id              = MID_KIOXIA,
        .dev_id              = DID_TC58CVG1S3HRAIJ,
        ._num_block          = SNAF_MODEL_NUM_BLK_2048,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_USE_ODE,
        #if __DEVICE_REASSIGN
            ._ecc_encode     = VZERO,
            ._ecc_decode     = VZERO,
            ._reset          = VZERO,
            ._cmd_info       = VZERO,
            ._model_info     = VZERO,
        #elif __DEVICE_USING_SIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_sio_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_DIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_x2_cmd_info,
            ._model_info     = &toshiba_general_model,
        #elif __DEVICE_USING_QIO
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &toshiba_x4_cmd_info,
            ._model_info     = &toshiba_general_model,
        #endif
    },
    {//This is for Default
        .man_id              = MID_TOSHIBA, 
        .dev_id              = DEFAULT_DATA_BASE,
        ._num_block          = SNAF_MODEL_NUM_BLK_1024,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_MODEL_6T,
        #if __DEVICE_REASSIGN
            ._ecc_encode     = VZERO,
            ._ecc_decode     = VZERO,
            ._reset          = VZERO,
            ._cmd_info       = VZERO,
            ._model_info     = VZERO,
        #else
            ._ecc_encode     = toshiba_ecc_encode,
            ._ecc_decode     = toshiba_ecc_decode,
            ._reset          = nsu_reset_spi_nand_chip,
            ._cmd_info       = &nsc_sio_cmd_info,
            ._model_info     = &toshiba_general_model,
        #endif
    },
};
#endif // CONFIG_SPI_NAND_FLASH_INIT_FIRST

__SECTION_INIT_PHASE_DATA
spi_nand_flash_info_t winbond_chip_info[] = {
    {
        .man_id              = MID_WINBOND,
        .dev_id              = DID_W25N01GV,
        ._num_block          = SNAF_MODEL_NUM_BLK_1024,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_MODEL_6T,
    #if __DEVICE_REASSIGN
        ._ecc_encode         = VZERO,
        ._ecc_decode         = VZERO,
        ._reset              = VZERO,
        ._model_info         = VZERO,
        ._cmd_info           = VZERO,
    #else
        ._ecc_encode         = ecc_encode_bch,
        ._ecc_decode         = ecc_decode_bch,
        ._reset              = nsu_reset_spi_nand_chip,
        ._model_info         = &snaf_rom_general_model,
        #if __DEVICE_USING_QIO
        ._cmd_info           = &winbond_qio_cmd_info,
        #elif __DEVICE_USING_DIO
        ._cmd_info           = &nsc_dio_cmd_info,
        #else
        ._cmd_info           = &nsc_sio_cmd_info,
        #endif
    #endif
    },{
        .man_id              = MID_WINBOND,
        .dev_id              = DID_W25N02KV,
        ._num_block          = SNAF_MODEL_NUM_BLK_2048,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B, //64B for internal ECC
        ._oob_size           = SNAF_MODEL_OOB_SIZE(62),
        ._ecc_ability        = ECC_USE_ODE,
    #if __DEVICE_REASSIGN
        ._ecc_encode         = VZERO,
        ._ecc_decode         = VZERO,
        ._reset              = VZERO,
        ._model_info         = VZERO,
        ._cmd_info           = VZERO,
    #else
        ._ecc_encode         = winbond_ecc_encode,
        ._ecc_decode         = winbond_ecc_decode,
        ._reset              = nsu_reset_spi_nand_chip,
        ._model_info         = &winbond_ode_model,
        #if __DEVICE_USING_QIO
        ._cmd_info           = &winbond_qio_cmd_info,
        #elif __DEVICE_USING_DIO
        ._cmd_info           = &nsc_dio_cmd_info,
        #else
        ._cmd_info           = &nsc_sio_cmd_info,
        #endif
    #endif
    },{//This is for Default
        .man_id              = MID_WINBOND,
        .dev_id              = DEFAULT_DATA_BASE,
        ._num_block          = SNAF_MODEL_NUM_BLK_1024,
        ._num_page_per_block = SNAF_MODEL_NUM_PAGE_64,
        ._page_size          = SNAF_MODEL_PAGE_SIZE_2048B,
        ._spare_size         = SNAF_MODEL_SPARE_SIZE_64B,
        ._oob_size           = SNAF_MODEL_OOB_SIZE(24),
        ._ecc_ability        = ECC_MODEL_6T,
    #if __DEVICE_REASSIGN
        ._ecc_encode         = VZERO,
        ._ecc_decode         = VZERO,
        ._reset              = VZERO,
        ._model_info         = VZERO,
        ._cmd_info           = VZERO,
    #else
        ._ecc_encode         = ecc_encode_bch,
        ._ecc_decode         = ecc_decode_bch,
        ._reset              = nsu_reset_spi_nand_chip,
        ._model_info         = &snaf_rom_general_model,
        ._cmd_info           = &nsc_sio_cmd_info,
    #endif
    }
};
#endif // CONFIG_SPI_NAND_FLASH_INIT_FIRST

./arch/otto40/plr/src/soc/spi_nand_gen2/spi_nand_toshiba.c:128:    ._block_erase = nsc_block_erase,
./arch/otto40/plr/src/soc/spi_nand_gen2/spi_nand_winbond.c:112:    ._block_erase = nsc_block_erase,
./drivers/mtd/spi/luna_spi_nand.c:278:        chip->_spi_nand_info->_model_info->_block_erase(chip->_spi_nand_info, page_addr);

------------------------------------------------
init_fnc_t *init_sequence[] = {
	board_early_init_f,
	timer_init,
	env_init,		/* initialize environment */
	//init_baudrate,	/* initialize baudrate settings */
	//serial_init,		/* serial communications setup */
	//console_init_f,
	display_banner,		/* say that we are here */
	checkboard,
	init_func_ram,
	NULL,
};
//loader\u-boot-2011.12\arch\otto40\lib\board.c
void board_init_f(ulong bootflag)
{
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0)
			hang();
	} 

./config.in:102:hex 'U-Boot Text Base' CONFIG_SYS_TEXT_BASE     0x83F00000
	board_init_r(id, CONFIG_SYS_TEXT_BASE);
}

loader\u-boot-2011.12\arch\otto40\lib\board.c
PATCH_REG(swp_flash_init, 1);
PATCH_REG(swp_env, 3);
PATCH_REG(swp_uart, 5);
#ifdef CONFIG_OTTO_FLASH_LAYOUT
PATCH_REG(swp_gen_fl, 5);
#endif /* #ifdef CONFIG_OTTO_FLASH_LAYOUT */
PATCH_REG(swp_pci, 7);
PATCH_REG(swp_studio, 9);
PATCH_REG(swp_console_r, 11);
PATCH_REG(swp_env_set, 13);
PATCH_REG(swp_spi, 15);
PATCH_REG(swp_misc, 17);
PATCH_REG(swp_post, 19);
PATCH_REG(swp_eth, 21); 

loader\u-boot-2011.12\arch\otto40\lib\board.c
  void board_init_r(gd_t *id, ulong dest_addr)
  {

	sw_patch_t **sw_patch = &LS_sw_patch_start;
	while (sw_patch!=&LS_bootm_stack) {
	    (*sw_patch)();
	    ++sw_patch;
	}	
  	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;)
		main_loop();
  }
loader\u-boot-2011.12\common\main.c
   void main_loop (void)


/*flash init , level 1*/
void swp_flash_init(void){
#ifndef CONFIG_SYS_NO_FLASH
	ulong size;
#endif
	bd_t *bd;

	bd = gd->bd;

#ifndef CONFIG_SYS_NO_FLASH
	size = flash_init();
	display_flash_config(size);
	bd->bi_flashsize = size;
#endif

#ifdef CONFIG_CMD_SF
	puts("SPI-F: ");
	spi_flash_init();
	bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
#endif

#if CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
	bd->bi_flashoffset = monitor_flash_len;	/* reserved area for U-Boot */
#else
	bd->bi_flashoffset = 0;
#endif
#if defined (CONFIG_CMD_SPI_NAND)
	spi_nand_init();
#endif
}  

loader\u-boot-2011.12\arch\otto40\lib\otto_spi_nand_flash.c

void spi_nand_init(void) {
#if 0
#if USE_BBT_SKIP
    u32_t _bbt_table[NUM_WORD(MAX_BLOCKS)];
#endif
#endif
    spi_nand_flash_info_t *fi;
    uint32_t count=1;

    /* fill spi nand info */
    fi = spi_nand_probe(&count);#检索nand flash芯片信息
    if(NULL==fi) return;
#关于OOB区,是每个Page都有的。Page大小是512字节的NAND每页分配16字节的OOB;如果NAND物理上
#是2K的Page,则每个Page分配64字节的OOB。不同型号的flash一个page的大小也不同, pagesize或
#者为512+16字节, 或者为2048+64字节; 
#以pagesize=2048+64的为例:2048字节是数据区,也被称为main area; 后面的64字节是OOB(out 
#of band), 也可以被成为spare area;
#if 0
Device:
 SPI-NAND, ID:c212, size:128 MB*1 
 each chip has           1024 block(s)
 each block has            64 page(s)
 page size               2048 byte(s)
 erase size            131072 byte(s)
 spare size                64 byte(s)
     oob size              24 byte(s)
     others                40 byte(s)

#nand-flash 擦除以一个块的单位大小擦除,写以一个页的单位大小读写     
#endif     
    _info.id = (fi->man_id << DEV_ID_LEN_BITS(fi->dev_id)) | fi->dev_id; #厂家身份ID
    _info.cs_count=count; #总共=有几块flash芯片
    _info.chip_size=SNAF_NUM_OF_BLOCK(fi)   #芯片总大小
                   *SNAF_NUM_OF_PAGE_PER_BLK(fi)
                   *SNAF_PAGE_SIZE(fi);
    _info.block_size=SNAF_NUM_OF_PAGE_PER_BLK(fi)  #每个块大小
                   *SNAF_PAGE_SIZE(fi);
    _info.page_size=SNAF_PAGE_SIZE(fi);   #每页大小,一页大小等于 = 页大小 + obb size; 
    _info.oob_size=SNAF_OOB_SIZE(fi);
    _info.spare_size=SNAF_SPARE_SIZE(fi);
    _info.block_count=SNAF_NUM_OF_BLOCK(fi); #一块flash总共有多少块
    _info.page_count=SNAF_NUM_OF_PAGE_PER_BLK(fi); #每个块包含多少页
    _info.flash_info = fi;

    printf("SPI-NAND Flash: %X/Mode%d %dx%uMB\n", _info.id, fi->_cmd_info->r_data_io, count, spi_nand_chip_size()>>20);
#if 0
    memset(_bbt_table, '\0', sizeof(_bbt_table));
    if(_info.block_count > MAX_BLOCKS){
        printf("SPI-NAND Flash: Create Bad Block Table Error!\n Block Number is More than %d!\n",  MAX_BLOCKS);
    }else{
        create_bbt(_bbt_table);
#if USE_BBT_SKIP
        create_skip_table(_bbt_table);
#endif
    }
#endif
#if defined(CONFIG_MTD_DEVICE) && defined(CONFIG_MTD_PARTITIONS)
#ifdef CONFIG_SPI_NAND_FLASH
./drivers/mtd/spi/luna_spi_nand.c:610:int rtk_spi_nand_init (void)
    rtk_spi_nand_init ();
#endif
#endif
}

struct mtd_info *rtk_mtd[2];
#define MTDSIZE	(sizeof (struct mtd_info) + sizeof (struct luna_nand_t))
int rtk_spi_nand_init (void)
{
	struct nand_chip *this = NULL;
	//spi_nand_flash_info_t *fi;
	int rc = 0;
    //uint32_t count=1;

	#申请一个mtd设备大小空间:mtd_info size  +  nand-info size;
    rtk_mtd[0] = kmalloc (MTDSIZE, GFP_KERNEL); //mtd_info struct + nand_chip struct
    if (!rtk_mtd[0]) {
		printk ("%s: Error, no enough memory for rtk_mtd\n", __FUNCTION__);
		rc = -1;//ENOMEM;
	}
    memset ((char *)rtk_mtd[0], 0, MTDSIZE);
#if 1
    #nand-flash info信息来自硬件探测得到的信息
    rtk_mtd[0]->priv = this = (struct nand_chip *)(rtk_mtd[0] + 1); 
#endif

    chip_count             = spi_nand_cs_count(); # 1块nand-flash芯片
    /* fill mtd info */
    rtk_mtd[0]->name       = "nand0";
    rtk_mtd[0]->size       = spi_nand_chip_size()*chip_count; #128*1M
    rtk_mtd[0]->erasesize  = spi_nand_block_size(); #64*2048
    rtk_mtd[0]->writesize  = spi_nand_page_size(); #2048
    rtk_mtd[0]->oobsize    = spi_nand_oob_size(); #24  =64(spare-size)=24(oob-sieze)+40(others)

    /* init spi nand flash */
    loader\u-boot-2011.12\drivers\mtd\spi\luna_spi_nand.c
    if (rtk_spi_nand_profile (rtk_mtd[0]) < 0) {
        rc = -1;
    }
	return rc;
}

loader\u-boot-2011.12\drivers\mtd\spi\luna_spi_nand.c
static int rtk_spi_nand_profile (struct mtd_info *mtd)
{
	//char *ptype;
	//int pnum = 0;
	//struct mtd_partition *mtd_parts;
    register struct luna_nand_t *chip = (struct luna_nand_t *)mtd->priv;

#loader\u-boot-2011.12\arch\otto40\cpu\mips1004kc\project\9300_nand_demo\platform\spi_nand\spi_nand_struct.h:struct spi_nand_flash_info_s
    chip->_spi_nand_info = spi_nand_flash_info();#填充来自硬件nand-flash探测得到的信息
#if 1
#if 0 注释
#loader\u-boot-2011.12\arch\otto40\cpu\mips1004kc\project\9300_nand_demo\platform\spi_nand\spi_nand_struct.h
static int
rtk_mtd_create_buffer(struct mtd_info *mtd)
{
	struct luna_nand_t *chip = (struct luna_nand_t *)mtd->priv;
    //const int bbt_table_len = (sizeof(*_bbt_table))*(NUM_WORD(SNAF_NUM_OF_BLOCK(chip->_spi_nand_info)));

    if (RTK_NAND_PAGE_BUF_SIZE < chip->_writesize + chip->_spare_size) {
        RTK_NAND_PAGE_BUF_SIZE = (chip->_writesize + chip->_spare_size);
	}
static unsigned char *_ecc_buf  = NULL;
static unsigned char *_page_buf = NULL;	
(sizeof(*_ecc_buf) == 1
(sizeof(*_page_buf) == 1
#./arch/otto40/include/asm/arch-rtl9300/soc.h:61:    #define MAX_ECC_BUF_SIZE 32	
	_ecc_buf   = kmalloc((sizeof(*_ecc_buf))*MAX_ECC_BUF_SIZE + 32, GFP_KERNEL);
	_page_buf  = kmalloc((sizeof(*_page_buf))*RTK_NAND_PAGE_BUF_SIZE + 32, GFP_KERNEL);

    // align
	chip->_ecc_buf   = (__typeof__(*_ecc_buf)*)(((uintptr_t)_ecc_buf+31) & ~ (uintptr_t)0x1F);
	chip->_page_buf  = (__typeof__(*_page_buf)*)(((uintptr_t)_page_buf+31) & ~ (uintptr_t)0x1F);

    if (!_ecc_buf || !_page_buf) {
		printk ("%s: Error, no enough memory for buffer\n", __FUNCTION__);
		return -12;//ENOMEM;
	} else {
		return 0;
	}
}
#endif
    if (rtk_mtd_create_buffer(mtd)) {
		return -1;
	}
#endif
#if 0 注释
static void
rtk_luna_nand_set(struct mtd_info *mtd)
{
	struct luna_nand_t *chip = (struct luna_nand_t *)mtd->priv;
    chip->_writesize = mtd->writesize;//2048bytes
	chip->_oob_poi =  (chip->_page_buf) + (chip->_writesize); //4096bytes
    chip->_spare_size = spi_nand_spare_size();//64bytes
}
    rtk_luna_nand_set(mtd);
#endif
#if 0

static void
rtk_nand_set(struct mtd_info *mtd)
{
	register struct nand_chip *chip = (struct nand_chip *)mtd->priv;

	if (!chip->chip_delay)
		chip->chip_delay = 20;

	chip->cmdfunc = rtk_nand_cmdfunc;
	chip->waitfunc = rtk_nand_waitfunc;

	chip->read_byte = rtk_nand_read_byte;
	chip->read_word = rtk_nand_read_word;
	chip->select_chip = rtk_nand_select_chip;
	chip->write_buf = rtk_nand_write_buf;
	chip->read_buf = rtk_nand_read_buf;
}
#endif
    rtk_nand_set(mtd);
#if 1
#if 0

static int
rtk_nand_ecc_set(struct mtd_info *mtd)
{
	struct luna_nand_t *chip = (struct luna_nand_t *)mtd->priv;
	register struct nand_ecc_ctrl *ecc = &(((struct nand_chip *)mtd->priv)->ecc);

	ecc->mode = NAND_ECC_HW;
	ecc->size = 512;
	ecc->bytes = 10;
	if (2048 == chip->_writesize) {
		ecc->layout = &nand_bch_oob_64;
	} else if (4096 == chip->_writesize ) {
		ecc->layout = &nand_bch_oob_128;
	} else {
		printk("%s: Error! unsupported page size %d\n", __FUNCTION__, chip->_writesize);
		return -1;
	}

    ecc->mode = NAND_ECC_HW;
	ecc->calculate = (void*)rtk_nand_bug;
	ecc->correct = (void*)rtk_nand_bug;
#loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
    ecc->read_page = rtk_nand_read_page;
    ecc->write_page = rtk_nand_write_page;
    ecc->read_page_raw = rtk_nand_read_page_raw;
    ecc->write_page_raw = rtk_nand_write_page_raw;
	ecc->read_subpage = (void*)rtk_nand_bug;
	ecc->strength = 6;
	return 0;
}
#endif
    if (rtk_nand_ecc_set(mtd))
		return -1;
#if 0
rtk_nand_ids(struct mtd_info *mtd)
{
	struct luna_nand_t *chip = (struct luna_nand_t *)mtd->priv;
    nand_flash_ids[0].name      = "ids0";
    nand_flash_ids[0].id        = chip->_spi_nand_info->dev_id >> ((chip->_spi_nand_info->dev_id&0xFF00)?8:0);
    nand_flash_ids[0].chipsize  = (mtd->size) >> 20;
    nand_flash_ids[0].pagesize  = mtd->writesize;
    nand_flash_ids[0].erasesize = mtd->erasesize;
    nand_flash_ids[0].options   = LUNA_SPI_OPTION;
}
#endif		
    rtk_nand_ids(mtd);
#endif
#if 1
#loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c:nand_scan
#if 0
int nand_scan(struct mtd_info *mtd, int maxchips)
{
	int ret;
#if 0
	int i, busw, nand_maf_id, nand_dev_id;
	struct nand_chip *chip = mtd->priv;
	const struct nand_flash_dev *type;

	/* Get buswidth to select the correct functions */
	busw = chip->options & NAND_BUSWIDTH_16;
	/* Set the default functions */
	nand_set_defaults(chip, busw);

#if 1
	loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
	static void single_erase_cmd(struct mtd_info *mtd, int page)
	{
		struct nand_chip *chip = mtd->priv;
		/* Send commands to erase a block */
		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
	}
	loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
		static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
								  struct nand_chip *chip,
								  int busw,
								  int *maf_id, int *dev_id,
								  const struct nand_flash_dev *type)
		{
			int ret, maf_idx;
			int tmp_id, tmp_manf;
		
			/* Select the device */
			chip->select_chip(mtd, 0);
		
			/*
			 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
			 * after power-up
			 */
			chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
		
			/* Send the command for reading device ID */
			chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
		
			/* Read manufacturer and device IDs */
			*maf_id = chip->read_byte(mtd);
			*dev_id = chip->read_byte(mtd);
		
			/* Try again to make sure, as some systems the bus-hold or other
			 * interface concerns can cause random data which looks like a
			 * possibly credible NAND flash to appear. If the two results do
			 * not match, ignore the device completely.
			 */
		
			chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
		
			/* Read manufacturer and device IDs */
		
			tmp_manf = chip->read_byte(mtd);
			tmp_id = chip->read_byte(mtd);
		
			if (tmp_manf != *maf_id || tmp_id != *dev_id) {
				printk(KERN_INFO "%s: second ID read did not match "
				       "%02x,%02x against %02x,%02x\n", __func__,
				       *maf_id, *dev_id, tmp_manf, tmp_id);
				return ERR_PTR(-ENODEV);
			}
		
			if (!type)
				type = nand_flash_ids;
		
			for (; type->name != NULL; type++)
				if (*dev_id == type->id)
					break;
		
			if (!type->name) {
				/* supress warning if there is no nand */
				if (*maf_id != 0x00 && *maf_id != 0xff &&
				    *dev_id  != 0x00 && *dev_id  != 0xff)
					printk(KERN_INFO "%s: unknown NAND device: "
						"Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
						__func__, *maf_id, *dev_id);
				return ERR_PTR(-ENODEV);
			}
		
			if (!mtd->name)
				mtd->name = type->name;
		
			chip->chipsize = (uint64_t)type->chipsize << 20;
			chip->onfi_version = 0;
		
			ret = nand_flash_detect_onfi(mtd, chip, &busw);
			if (!ret)
				nand_flash_detect_non_onfi(mtd, chip, type, &busw);
		
			/* Get chip options, preserve non chip based options */
			chip->options &= ~NAND_CHIPOPTIONS_MSK;
			chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
		
			/*
			 * Set chip as a default. Board drivers can override it, if necessary
			 */
			chip->options |= NAND_NO_AUTOINCR;
#if 0
loader\u-boot-2011.12\drivers\mtd\nand\nand_ids.c
const struct nand_manufacturers nand_manuf_ids[] = {
	{NAND_MFR_TOSHIBA, "Toshiba"},
	{NAND_MFR_SAMSUNG, "Samsung"},
	{NAND_MFR_FUJITSU, "Fujitsu"},
	{NAND_MFR_NATIONAL, "National"},
	{NAND_MFR_RENESAS, "Renesas"},
	{NAND_MFR_STMICRO, "ST Micro"},
	{NAND_MFR_HYNIX, "Hynix"},
	{NAND_MFR_MICRON, "Micron"},
	{NAND_MFR_AMD, "AMD"},
	{0x0, "Unknown"}
};	
#endif	
			/* Try to identify manufacturer */
			for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
				if (nand_manuf_ids[maf_idx].id == *maf_id)
					break;
			}
		
			/*
			 * Check, if buswidth is correct. Hardware drivers should set
			 * chip correct !
			 */
			if (busw != (chip->options & NAND_BUSWIDTH_16)) {
				printk(KERN_INFO "NAND device: Manufacturer ID:"
				       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
				       *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
				printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
				       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
				       busw ? 16 : 8);
				return ERR_PTR(-EINVAL);
			}
		
			/* Calculate the address shift from the page size */
			chip->page_shift = ffs(mtd->writesize) - 1;
			/* Convert chipsize to number of pages per chip -1. */
			chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
		
			chip->bbt_erase_shift = chip->phys_erase_shift =
				ffs(mtd->erasesize) - 1;
			if (chip->chipsize & 0xffffffff)
				chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
			else
				chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
		
			/* Set the bad block position */
			chip->badblockpos = mtd->writesize > 512 ?
				NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
		
			/* Check if chip is a not a samsung device. Do not clear the
			 * options for chips which are not having an extended id.
			 */
			if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
				chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
		
			/* Check for AND chips with 4 page planes */
			if (chip->options & NAND_4PAGE_ARRAY)
				chip->erase_cmd = multi_erase_cmd;
			else
				chip->erase_cmd = single_erase_cmd;
		
			/* Do not replace user supplied command function ! */
			if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
				chip->cmdfunc = nand_command_lp;
		
			MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
				  " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
				  nand_manuf_ids[maf_idx].name, type->name);
		
			return type;
		}
	/* Read the flash type */
	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, &nand_dev_id, table);
#endif

	if (IS_ERR(type)) {
#ifndef CONFIG_SYS_NAND_QUIET_TEST
		printk(KERN_WARNING "No NAND device found!!!\n");
#endif
		chip->select_chip(mtd, -1);
		return PTR_ERR(type);
	}

	/* Check for a chip array */
	for (i = 1; i < maxchips; i++) {
		chip->select_chip(mtd, i);
		/* See comment in nand_get_flash_type for reset */
		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
		/* Send the command for reading device ID */
		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
		/* Read manufacturer and device IDs */
		if (nand_maf_id != chip->read_byte(mtd) ||
		    nand_dev_id != chip->read_byte(mtd))
			break;
	}
	/* Store the number of chips and calc total size for mtd */
	chip->numchips = i;
	mtd->size = i * chip->chipsize;

	return 0;
}
#endif
	ret = nand_scan_ident(mtd, maxchips, NULL);
	if (!ret)
		ret = nand_scan_tail(mtd);
	return ret;
}
#endif
    if(nand_scan(mtd, 1)){
		printk ("Warning: rtk nand scan error!\n");
		return -1;
	}
#endif

    rtk_luna_nand_chk(mtd);

#if 1
	/* check page size(write size) is 512/2048/4096.. must 512byte align */
    if (!(mtd->writesize & (0x200 - 1)))
		;//rtk_writel( rtk_mtd->oobblock >> 9, REG_PAGE_LEN);
	else {
		printk ("Error: pagesize is not 512Byte Multiple");
		return -1;
	}
#endif

#ifdef CONFIG_MTD_CMDLINE_PARTS
	/* partitions from cmdline */
	ptype = (char *)ptypes[0];
	pnum = parse_mtd_partitions (rtk_mtd, ptypes, &mtd_parts, 0);

	if (pnum <= 0) {
		printk (KERN_NOTICE "RTK: using the whole nand as a partitoin\n");
		if (add_mtd_device (rtk_mtd)) {
			printk (KERN_WARNING "RTK: Failed to register new nand device\n");
			return -EAGAIN;
		}
	} else {
		printk (KERN_NOTICE "RTK: using dynamic nand partition\n");
		if (add_mtd_partitions (rtk_mtd, mtd_parts, pnum)) {
			printk("%s: Error, cannot add %s device\n",
					__FUNCTION__, rtk_mtd->name);
			rtk_mtd->size = 0;
			return -EAGAIN;
		}
	}
#else
	/* fixed partition ,modify rtl8686_parts table*/
	printk("RTK: Register new nand device\n");
#if 0

struct mtd_info *mtd_table[MAX_MTD_DEVICES];

int add_mtd_device(struct mtd_info *mtd)
{
	int i;

	BUG_ON(mtd->writesize == 0);

	for (i = 0; i < MAX_MTD_DEVICES; i++)
		if (!mtd_table[i]) {
			mtd_table[i] = mtd;
			mtd->index = i;
			mtd->usecount = 0;
			return 0;
		}
	return 1;
}
#./drivers/mtd/mtdcore.c:16:int add_mtd_device(struct mtd_info *mtd)
    if (add_mtd_device (mtd)) {
		printk(KERN_WARNING "RTK: Failed to register new nand device\n");
		//return -EAGAIN;
		return -11;
	}
#endif	
#endif
	return 0;
}

static void nand_set_defaults(struct nand_chip *chip, int busw)
{
	if (!chip->block_bad)
		chip->block_bad = nand_block_bad;
	if (!chip->block_markbad)
		chip->block_markbad = nand_default_block_markbad;

	if (!chip->verify_buf)
		chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
	if (!chip->scan_bbt)
		chip->scan_bbt = nand_default_bbt;
	if (!chip->controller)
		chip->controller = &chip->hwcontrol;
}


int nand_scan_tail(struct mtd_info *mtd)
{
	int i;
	struct nand_chip *chip = mtd->priv;

	if (!(chip->options & NAND_OWN_BUFFERS))
		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
	if (!chip->buffers)
		return -ENOMEM;

	/* Set the internal oob buffer location, just after the page data */
	chip->oob_poi = chip->buffers->databuf + mtd->writesize;

	if (!chip->write_page)
		chip->write_page = nand_write_page;

	/*
	 * check ECC mode, default to software if 3byte/512byte hardware ECC is
	 * selected and we have 256 byte pagesize fallback to software ECC
	 */

	switch (chip->ecc.mode) {
	case NAND_ECC_HW:
		if (!chip->ecc.read_oob)
			chip->ecc.read_oob = nand_read_oob_std;
		if (!chip->ecc.write_oob)
			chip->ecc.write_oob = nand_write_oob_std;
	default:
		printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
		       chip->ecc.mode);
		BUG();
	}

	/*
	 * The number of bytes available for a client to place data into
	 * the out of band area
	 */
	chip->ecc.layout->oobavail = 0;
	for (i = 0; chip->ecc.layout->oobfree[i].length
			&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
		chip->ecc.layout->oobavail +=
			chip->ecc.layout->oobfree[i].length;
	mtd->oobavail = chip->ecc.layout->oobavail;

	/*
	 * Set the number of read / write steps for one page depending on ECC
	 * mode
	 */
	chip->ecc.steps = mtd->writesize / chip->ecc.size;
	if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
		printk(KERN_WARNING "Invalid ecc parameters\n");
		BUG();
	}
	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;

	/*
	 * Allow subpage writes up to ecc.steps. Not possible for MLC
	 * FLASH.
	 */
	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
	    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
		switch(chip->ecc.steps) {
		case 2:
			mtd->subpage_sft = 1;
			break;
		case 4:
		case 8:
		case 16:
			mtd->subpage_sft = 2;
			break;
		}
	}
	chip->subpagesize = mtd->writesize >> mtd->subpage_sft;

	/* Initialize state */
	chip->state = FL_READY;

	/* De-select the device */
	chip->select_chip(mtd, -1);

	/* Invalidate the pagebuffer reference */
	chip->pagebuf = -1;
loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
	/* Fill in remaining MTD driver data */
	mtd->type = MTD_NANDFLASH;
	mtd->flags = MTD_CAP_NANDFLASH;
	mtd->erase = nand_erase;
	mtd->point = NULL;
	mtd->unpoint = NULL;
	mtd->read = nand_read;
	mtd->write = nand_write;
	mtd->read_oob = nand_read_oob;
	mtd->write_oob = nand_write_oob;
	mtd->sync = nand_sync;
	mtd->lock = NULL;
	mtd->unlock = NULL;
	mtd->block_isbad = nand_block_isbad;
	mtd->block_markbad = nand_block_markbad;

	/* propagate ecc.layout to mtd_info */
	mtd->ecclayout = chip->ecc.layout; #&nand_bch_oob_64;

	/* Check, if we should skip the bad block table scan */
	if (chip->options & NAND_SKIP_BBTSCAN)
		chip->options |= NAND_BBT_SCANNED;

	return 0;
}

#ifdef CONFIG_SPI_NAND_FLASH_INIT_F
IRST
extern spi_nand_flash_info_t        ub_spi_nand_flash_info;
#define _plr_spi_nand_info          (&ub_spi_nand_flash_info)
#else // CONFIG_SPI_NAND_FLASH_INIT_FIRST
#define _plr_soc_t                  (*(soc_t *)(OTTO_SRAM_START+OTTO_HEADER_OFFSET))
#define _plr_spi_nand_info          _plr_soc_t.flash_info.spi_nand_info
#endif // CONFIG_SPI_NAND_FLASH_INIT_FIRST

================================================================
nand-flash分区
kernel\uClinux\linux-4.4.x\drivers\mtd\mtdpart.c

struct nand_oobinfo {
	uint32_t useecc;
	uint32_t eccbytes;
	uint32_t oobfree[8][2];
	uint32_t eccpos[48];
};

struct nand_oobfree {
	uint32_t offset;
	uint32_t length;
};

#define MTD_MAX_OOBFREE_ENTRIES	8
/*
 * ECC layout control structure. Exported to userspace for
 * diagnosis and to allow creation of raw images
 */
struct nand_ecclayout {
	uint32_t eccbytes;
	uint32_t eccpos[128];
	uint32_t oobavail;
	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};

/**
 * struct mtd_ecc_stats - error correction stats
 *
 * @corrected:	number of corrected bits
 * @failed:	number of uncorrectable errors
 * @badblocks:	number of bad blocks in this partition
 * @bbtblocks:	number of blocks reserved for bad block tables
 */
struct mtd_ecc_stats {
	uint32_t corrected;
	uint32_t failed;
	uint32_t badblocks;
	uint32_t bbtblocks;
};

#if 0

#ifdef CONFIG_MTD_CMDLINE_PARTS
/* for fixed partition */
const char *ptypes[] = {"cmdlinepart", NULL};
//const char *ptypes[] = {"mtdparts=rtk_nand:640k@0(boot),6M@0x180000(linux),-(rootfs)", NULL};
#else
//eric, use cmdlinepart now

struct mtd_partition {
	char *name;			/* identifier string */
	uint64_t size;			/* partition size */
	uint64_t offset;		/* offset within the master MTD space */
	u_int32_t mask_flags;		/* master MTD flags to mask out for this partition */
	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only)*/
	struct mtd_info **mtdp;		/* pointer to store the MTD object */
};
static struct mtd_partition def_parts[] = {
    { name: "boot",     offset: 0,          size: 0x100000,     mask_flags:0},
    { name: "env",      offset: 0x100000,   size: 0x20000,      mask_flags:0},
    { name: "env",      offset: 0x120000,   size: 0x20000,      mask_flags:0},
};
#endif
#endif

#ifdef CONFIG_MTD_CMDLINE_PARTS
	/* partitions from cmdline */
	ptype = (char *)ptypes[0];
	struct mtd_info *rtk_mtd[2]; rtk_mtd[0]
	pnum = parse_mtd_partitions (rtk_mtd, ptypes, &mtd_parts, 0);

	if (pnum <= 0) {
		printk (KERN_NOTICE "RTK: using the whole nand as a partitoin\n");
		if (add_mtd_device (rtk_mtd)) {
			printk (KERN_WARNING "RTK: Failed to register new nand device\n");
			return -EAGAIN;
		}
	} else {
		printk (KERN_NOTICE "RTK: using dynamic nand partition\n");
		if (add_mtd_partitions (rtk_mtd, mtd_parts, pnum)) {
			printk("%s: Error, cannot add %s device\n",
					__FUNCTION__, rtk_mtd->name);
			rtk_mtd->size = 0;
			return -EAGAIN;
		}
	}
#else
	/* fixed partition ,modify rtl8686_parts table*/
	printk("RTK: Register new nand device\n");

    if (add_mtd_device (mtd)) {
		printk(KERN_WARNING "RTK: Failed to register new nand device\n");
		//return -EAGAIN;
		return -11;
	}
#endif

/*
 * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
 * are changing this array!
 */
static const char * const default_mtd_part_types[] = {
	"cmdlinepart",
	"ofpart",
	NULL
};


int add_mtd_partitions(struct mtd_info *master,
		       const struct mtd_partition *parts,
		       int nbparts)
{
	struct mtd_part *slave;
	uint64_t cur_offset = 0;
	int i;

	/*
	 * Need to init the list here, since LIST_INIT() does not
	 * work on platforms where relocation has problems (like MIPS
	 * & PPC).
	 */
	if (mtd_partitions.next == NULL)
		INIT_LIST_HEAD(&mtd_partitions);

	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);

	for (i = 0; i < nbparts; i++) {
		slave = add_one_partition(master, parts + i, i, cur_offset);
		if (!slave)
			return -ENOMEM;
		cur_offset = slave->offset + slave->mtd.size;
	}

	return 0;
}


static struct mtd_part *add_one_partition(struct mtd_info *master,
		const struct mtd_partition *part, int partno,
		uint64_t cur_offset)
{
	struct mtd_part *slave;

	/* allocate the partition structure */
	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
	if (!slave) {
		printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
			master->name);
		del_mtd_partitions(master);
		return NULL;
	}
	#总要节点
	list_add(&slave->list, &mtd_partitions);

	/* set up the MTD object for this partition */
	slave->mtd.type = master->type;
	slave->mtd.flags = master->flags & ~part->mask_flags;
	slave->mtd.size = part->size;
	slave->mtd.writesize = master->writesize;
	slave->mtd.oobsize = master->oobsize;
	slave->mtd.oobavail = master->oobavail;
	slave->mtd.subpage_sft = master->subpage_sft;

	slave->mtd.name = part->name;
	slave->mtd.owner = master->owner;

	slave->mtd.read = part_read;
	slave->mtd.write = part_write;

	if (master->panic_write)
		slave->mtd.panic_write = part_panic_write;

	if (master->read_oob)
		slave->mtd.read_oob = part_read_oob;
	if (master->write_oob)
		slave->mtd.write_oob = part_write_oob;
	if (master->read_user_prot_reg)
		slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
	if (master->read_fact_prot_reg)
		slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
	if (master->write_user_prot_reg)
		slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
	if (master->lock_user_prot_reg)
		slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
	if (master->get_user_prot_info)
		slave->mtd.get_user_prot_info = part_get_user_prot_info;
	if (master->get_fact_prot_info)
		slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
	if (master->sync)
		slave->mtd.sync = part_sync;
	if (master->lock)
		slave->mtd.lock = part_lock;
	if (master->unlock)
		slave->mtd.unlock = part_unlock;
	if (master->block_isbad)
		slave->mtd.block_isbad = part_block_isbad;
	if (master->block_markbad)
		slave->mtd.block_markbad = part_block_markbad;
	slave->mtd.erase = part_erase;
	slave->master = master;
	slave->offset = part->offset;
	slave->index = partno;

	if (slave->mtd.size == MTDPART_SIZ_FULL)
		slave->mtd.size = master->size - slave->offset;

	printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
		(unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);

	/* let's do some sanity checks */
	if (slave->offset >= master->size) {
		/* let's register it anyway to preserve ordering */
		slave->offset = 0;
		slave->mtd.size = 0;
		printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
			part->name);
		goto out_register;
	}
	if (slave->offset + slave->mtd.size > master->size) {
		slave->mtd.size = master->size - slave->offset;
		printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
			part->name, master->name, (unsigned long long)slave->mtd.size);
	}
	if (master->numeraseregions > 1) {
		/* Deal with variable erase size stuff */
		int i, max = master->numeraseregions;
		u64 end = slave->offset + slave->mtd.size;
		struct mtd_erase_region_info *regions = master->eraseregions;

		/* Find the first erase regions which is part of this
		 * partition. */
		for (i = 0; i < max && regions[i].offset <= slave->offset; i++)
			;
		/* The loop searched for the region _behind_ the first one */
		i--;

		/* Pick biggest erasesize */
		for (; i < max && regions[i].offset < end; i++) {
			if (slave->mtd.erasesize < regions[i].erasesize) {
				slave->mtd.erasesize = regions[i].erasesize;
			}
		}
		BUG_ON(slave->mtd.erasesize == 0);
	} else {
		/* Single erase size */
		slave->mtd.erasesize = master->erasesize;
	}

	if ((slave->mtd.flags & MTD_WRITEABLE) &&
	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
		/* Doesn't start on a boundary of major erase size */
		/* FIXME: Let it be writable if it is on a boundary of
		 * _minor_ erase size though */
		slave->mtd.flags &= ~MTD_WRITEABLE;
		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
			part->name);
	}
	if ((slave->mtd.flags & MTD_WRITEABLE) &&
	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
		slave->mtd.flags &= ~MTD_WRITEABLE;
		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
			part->name);
	}

	slave->mtd.ecclayout = master->ecclayout;
	if (master->block_isbad) {
		uint64_t offs = 0;

		while (offs < slave->mtd.size) {
			if (master->block_isbad(master,
						offs + slave->offset))
				slave->mtd.ecc_stats.badblocks++;
			offs += slave->mtd.erasesize;
		}
	}

out_register:
	if (part->mtdp) {
		/* store the object pointer (caller may or may not register it*/
		*part->mtdp = &slave->mtd;
		slave->registered = 0;
	} else {
		/* register our partition */
     	./include/linux/mtd/mtd.h:16:#define MAX_MTD_DEVICES 32
		./drivers/mtd/mtdcore.c:16:int add_mtd_device(struct mtd_info *mtd)
		add_mtd_device(&slave->mtd);
		slave->registered = 1;
	}
	return slave;
}

int add_mtd_device(struct mtd_info *mtd)
{
	int i;

	BUG_ON(mtd->writesize == 0);

	for (i = 0; i < MAX_MTD_DEVICES; i++)
		if (!mtd_table[i]) {
			mtd_table[i] = mtd;
			mtd->index = i;
			mtd->usecount = 0;
			return 0;
		}

	return 1;
}

loader\u-boot-2011.12\common\cmd_nvedit.c

U_BOOT_CMD_COMPLETE(
	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
	"set environment variables",
	"name value ...\n"
	"    - set environment variable 'name' to 'value ...'\n"
	"setenv name\n"
	"    - delete environment variable 'name'",
	var_complete
);

关于mtd->write_oob()和chip->ecc.write_oob(),具体有何区别和联系,
自己之前无意间注意到,也迷惑过,但并没有去弄懂,这次看到别人有提问,所以,专门去看了源码,基本算是搞清楚了。

mtd->write_oob,是在nand_scan()->nand_scan_tail()中被赋值的:
mtd->write_oob = nand_write_oob;
那我们就去看看nand_write_oob(),它主要是根据输入参数,决定具体做什么事情:
1.当输入参数中的页数据缓存是空的话,那么就去只是去写oob的数据,也就是单纯的写oob,而不写整个页的数据,也就只调用
nand_do_write_oob()去真正写oob的数据。
2.当输入参数中的页数据缓存pagebuf非空的话,那么不仅写页数据,而且还写oob。
具体调用的函数nand_do_write_ops()去实现既写整页数据,又写oob信息。

而此函数的功能,其实从函数功能的注释中,也可以看得很清楚:NAND write data and/or out-of-band。

下面就分别来看看上面两个数据的具体执行过程。
1.nand_do_write_oob
此函数简单说就是,先填充oob信息,即根据ecc的layout,调用nand_fill_oob,把ecc填充到buffer中;
然后调用chip->ecc.write_oob()去真正实现将oob写入到nand flash中。
至此,mtd->write_oob和ecc.write_oob的其中一种联系,就已经很清楚了:
mtd->write_oob中,如果只是写oob,那么调用nand_do_write_oob()->ecc.write_oob(),
完成oob的实际的写操作。

2.nand_do_write_ops
简单点说就是,先根据设置决定是否去调用nand_fill_oob填充oob,然后再去调用
chip->write_page实现真正页数据的写操作。
对于chip->write_page再解释一下,如果你没有自己实现此函数的话,
也是在nand_scan()->nand_scan_tail()中被赋值成系统默认的:
chip->write_page = nand_write_page;
而nand_write_page()中,根据是否是是raw,去调用不同的函数:
(1)chip->ecc.write_page_raw
关于raw:也就是raw原始数据以及oob,没有在oob中添加ecc信息的。
nand_scan_tail()中:
chip->ecc.write_page_raw = nand_write_page_raw;
nand_write_page_raw()中直接就是先写页数据,再写oob,没有具体去计算ecc并写入,
所以,和我们此处讨论的ecc没啥关系。
(2)chip->ecc.write_page
对于nand 的ecc类型是最常见的NAND_ECC_HW的话,
nand_scan_tail()中:
chip->ecc.write_page = nand_write_page_hwecc;
nand_write_page_hwecc()中,循环ecc的step次
(常见的是,页大小是2K的nand,每512字节产生6位或8位ecc值,ecc的step值就是,
页大小/一次ecc对应数据大小=2k/512=4),
先写启用硬件ecc校验,再写页数据,
然后把得到的ecc校验值组织好,放到oob中对应位置,然后再调用底层的写函数,去写ecc。
这部分,和我们上面的ecc.write_oob,也没有直接关系。

只不过,无论是写页数据,还是写oob数据,底层具体去写的动作,都是调用chip->write_buf()去实现的。
而nand_write_page_hwecc()中后面的写oob的部分,其实和ecc.write_oob是一样的,只不过没单独再去分开而已。

【总结】
mtd->write_oob()和chip->ecc.write_oob()的联系:
1.mtd->write_oob中,如果只是写oob,那么调用nand_do_write_oob()->ecc.write_oob(),
完成oob的实际的写操作。
2.mtd->write_oob中,如果即写页数据又写oob数据,并且是带ecc的写页数据的话,调用
chip->ecc.write_page去实现具体的先写页数据,再写含ecc的oob数据,具体最后的写含ecc的oob的过程,
本质上和ecc.write_oob,底层调用函数实现机制,都是一样的。

【题外话】
1.底层如何定位到oob的起始位置?
中间有个细节,本来很简单清楚的,差点把自己搞晕了,那就是:
对于写oob,到底底层是怎么传入参数使得定位到一个页的oob的起始位置的,然后再开始写oob数据的。
结果就是,再nand_write_oob_std()中,发命令的时候,送的就是定位的起始地址:
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
其中,mtd->writesize就是页内地址,此处就是一个页大小,比如2K,页结束地址=oob开始的位置,
就可以定位到oob起始处了,后面就可以写oob数据了:
chip->write_buf(mtd, buf, length);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

the future c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值