理一下uboot的nand操作相关

一、linux MTD驱动层次简介,from:http://www.cnblogs.com/hoys/archive/2012/05/30/2526230.html

MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。MTD的主要目的是为了使新的memory设备的驱 动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。MTD的所有源代码在/drivers/mtd子目录下。我将CFI接口的MTD设备分为四层 (从设备节点直到底层硬件驱动),这四层从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。

  一、Flash硬件驱动层:硬件驱动层负责在init时驱动Flash硬件,Linux MTD设备的NOR Flash芯片驱动遵循CFI接口标准,其驱动程序位于drivers/mtd/chips子目录下。NAND型Flash的驱动程序则位于/drivers/mtd/nand子目录下。

  二、MTD原始设备:原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是各个特定的Flash的数据,例如分区。 用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和操作函数。mtd_table(mtdcore.c)则是所有MTD原始设备的列表,mtd_part(mtd_part.c)是用于表示MTD原始设备分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,mtd_part.mtd_info中的大部分数据都从该分区的主分区mtd_part->master中获得。 在drivers/mtd/maps/子目录下存放的是特定的flash的数据,每一个文件都描述了一块板子上的flash。其中调用add_mtd_device()、del_mtd_device()建立/删除mtd_info结构并将其加入/删除mtd_table(或者调用add_mtd_partition()、del_mtd_partition()(mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除mtd_table 中)。

  三、MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。MTD字符设备的定义在mtdchar.c中实现,通过注册一系列file operation函数(lseek、open、close、read、write)。MTD块设备则是定义了一个描述MTD块设备的结构mtdblk_dev,并声明了一个名为mtdblks的指针数组,这数组中的每一个mtdblk_dev和mtd_table中的每一个mtd_info一一对应。

  四、设备节点:通过mknod在/dev子目录下建立MTD字符设备节点(主设备号为90)和MTD块设备节点(主设备号为31),通过访问此设备节点即可访问MTD字符设备和块设备。

  五、根文件系统:在Bootloader中将JFFS(或JFFS2)的文件系统映像jffs.image(或jffs2.img)烧到flash的某一个分区中,在/arch/arm/mach-your/arch.c文件的your_fixup函数中将该分区作为根文件系统挂载。

  六、文件系统:内核启动后,通过mount 命令可以将flash中的其余分区作为文件系统挂载到mountpoint上。

PS:因为uboot 的nand部分是移植linux内核驱动而来,所以熟悉一下这个比较好。


二、在uboot中用到的MTD的重要几个结构体


/**
 * struct nand_ecc_ctrl - Control structure for ecc
 * @mode:	ecc mode
 * @steps:	number of ecc steps per page
 * @size:	data bytes per ecc step
 * @bytes:	ecc bytes per step
 * @total:	total number of ecc bytes per page
 * @prepad:	padding information for syndrome based ecc generators
 * @postpad:	padding information for syndrome based ecc generators
 * @layout:	ECC layout control struct pointer
 * @priv:	pointer to private ecc control data
 * @hwctl:	function to control hardware ecc generator. Must only
 *		be provided if an hardware ECC is available
 * @calculate:	function for ecc calculation or readback from ecc hardware
 * @correct:	function for ecc correction, matching to ecc generator (sw/hw)
 * @read_page_raw:	function to read a raw page without ECC
 * @write_page_raw:	function to write a raw page without ECC
 * @read_page:	function to read a page according to the ecc generator
 *		requirements.
 * @read_subpage:	function to read parts of the page covered by ECC.
 * @write_page:	function to write a page according to the ecc generator
 *		requirements.
 * @read_oob:	function to read chip OOB data
 * @write_oob:	function to write chip OOB data
 */
struct nand_ecc_ctrl {
	nand_ecc_modes_t mode;
	int steps;
	int size;
	int bytes;
	int total;
	int prepad;
	int postpad;
	struct nand_ecclayout	*layout;
	void *priv;
	void (*hwctl)(struct mtd_info *mtd, int mode);
	int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
			uint8_t *ecc_code);
	int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
			uint8_t *calc_ecc);
	int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
			uint8_t *buf, int page);
	void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
			const uint8_t *buf);
	int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
			uint8_t *buf, int page);
	int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
			uint32_t offs, uint32_t len, uint8_t *buf);
	void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
			const uint8_t *buf);
	int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
			int sndcmd);
	int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
			int page);
};


struct mtd_info {
	u_char type;
	u_int32_t flags;
	uint64_t size;	 /* Total size of the MTD */

	/* "Major" erase size for the device. Na茂ve users may take this
	 * to be the only erase size available, or may use the more detailed
	 * information below if they desire
	 */
	u_int32_t erasesize;
	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
	 * though individual bits can be cleared), in case of NAND flash it is
	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
	 * it is of ECC block size, etc. It is illegal to have writesize = 0.
	 * Any driver registering a struct mtd_info must ensure a writesize of
	 * 1 or larger.
	 */
	u_int32_t writesize;

	u_int32_t oobsize;   /* Amount of OOB data per block (e.g. 16) */
	u_int32_t oobavail;  /* Available OOB bytes per block */

	/* Kernel-only stuff starts here. */
	const char *name;
	int index;

	/* ecc layout structure pointer - read only ! */
	struct nand_ecclayout *ecclayout;

	/* Data for variable erase regions. If numeraseregions is zero,
	 * it means that the whole device has erasesize as given above.
	 */
	int numeraseregions;
	struct mtd_erase_region_info *eraseregions;

	/*
	 * Erase is an asynchronous operation.  Device drivers are supposed
	 * to call instr->callback() whenever the operation completes, even
	 * if it completes with a failure.
	 * Callers are supposed to pass a callback function and wait for it
	 * to be called before writing to the block.
	 */
	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);

	/* This stuff for eXecute-In-Place */
	/* phys is optional and may be set to NULL */
	int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
			size_t *retlen, void **virt, phys_addr_t *phys);

	/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
	void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);


	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

	/* In blackbox flight recorder like scenarios we want to make successful
	   writes in interrupt context. panic_write() is only intended to be
	   called when its known the kernel is about to panic and we need the
	   write to succeed. Since the kernel is not going to be running for much
	   longer, this function can break locks and delay to ensure the write
	   succeeds (but not sleep). */

	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

	int (*read_oob) (struct mtd_info *mtd, loff_t from,
			 struct mtd_oob_ops *ops);
	int (*write_oob) (struct mtd_info *mtd, loff_t to,
			 struct mtd_oob_ops *ops);

	/*
	 * Methods to access the protection register area, present in some
	 * flash devices. The user data is one time programmable but the
	 * factory data is read only.
	 */
	int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);

/* XXX U-BOOT XXX */
#if 0
	/* kvec-based read/write methods.
	   NB: The 'count' parameter is the number of _vectors_, each of
	   which contains an (ofs, len) tuple.
	*/
	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
#endif

	/* Sync */
	void (*sync) (struct mtd_info *mtd);

	/* Chip-supported device locking */
	int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
	int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);

	/* Bad block management functions */
	int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
	int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);

/* XXX U-BOOT XXX */
#if 0
	struct notifier_block reboot_notifier;  /* default mode before reboot */
#endif

	/* ECC status information */
	struct mtd_ecc_stats ecc_stats;
	/* Subpage shift (NAND) */
	int subpage_sft;

	void *priv;

	struct module *owner;
	int usecount;

	/* If the driver is something smart, like UBI, it may need to maintain
	 * its own reference counting. The below functions are only for driver.
	 * The driver may register its callbacks. These callbacks are not
	 * supposed to be called by MTD users */
	int (*get_device) (struct mtd_info *mtd);
	void (*put_device) (struct mtd_info *mtd);
#if defined(CONFIG_CMD_NAND_YAFFS)
         u_char rw_oob;
         u_char skipfirstblk;
#endif
};

/**
 * struct nand_chip - NAND Private Flash Chip Data
 * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the
 *			flash device
 * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the
 *			flash device.
 * @read_byte:		[REPLACEABLE] read one byte from the chip
 * @read_word:		[REPLACEABLE] read one word from the chip
 * @write_buf:		[REPLACEABLE] write data from the buffer to the chip
 * @read_buf:		[REPLACEABLE] read data from the chip into the buffer
 * @verify_buf:		[REPLACEABLE] verify buffer contents against the chip
 *			data.
 * @select_chip:	[REPLACEABLE] select chip nr
 * @block_bad:		[REPLACEABLE] check, if the block is bad
 * @block_markbad:	[REPLACEABLE] mark the block bad
 * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific function for controlling
 *			ALE/CLE/nCE. Also used to write command and address
 * @init_size:		[BOARDSPECIFIC] hardwarespecific function for setting
 *			mtd->oobsize, mtd->writesize and so on.
 *			@id_data contains the 8 bytes values of NAND_CMD_READID.
 *			Return with the bus width.
 * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accesing
 *			device ready/busy line. If set to NULL no access to
 *			ready/busy is available and the ready/busy information
 *			is read from the chip status register.
 * @cmdfunc:		[REPLACEABLE] hardwarespecific function for writing
 *			commands to the chip.
 * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on
 *			ready.
 * @ecc:		[BOARDSPECIFIC] ecc control ctructure
 * @buffers:		buffer structure for read/write
 * @hwcontrol:		platform-specific hardware control structure
 * @ops:		oob operation operands
 * @erase_cmd:		[INTERN] erase command write function, selectable due
 *			to AND support.
 * @scan_bbt:		[REPLACEABLE] function to scan bad block table
 * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transferring
 *			data from array to read regs (tR).
 * @state:		[INTERN] the current state of the NAND device
 * @oob_poi:		poison value buffer
 * @page_shift:		[INTERN] number of address bits in a page (column
 *			address bits).
 * @phys_erase_shift:	[INTERN] number of address bits in a physical eraseblock
 * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry
 * @chip_shift:		[INTERN] number of address bits in one chip
 * @options:		[BOARDSPECIFIC] various chip options. They can partly
 *			be set to inform nand_scan about special functionality.
 *			See the defines for further explanation.
 * @badblockpos:	[INTERN] position of the bad block marker in the oob
 *			area.
 * @badblockbits:	[INTERN] number of bits to left-shift the bad block
 *			number
 * @cellinfo:		[INTERN] MLC/multichip data from chip ident
 * @numchips:		[INTERN] number of physical chips
 * @chipsize:		[INTERN] the size of one chip for multichip arrays
 * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1
 * @pagebuf:		[INTERN] holds the pagenumber which is currently in
 *			data_buf.
 * @subpagesize:	[INTERN] holds the subpagesize
 * @onfi_version:	[INTERN] holds the chip ONFI version (BCD encoded),
 *			non 0 if ONFI supported.
 * @onfi_params:	[INTERN] holds the ONFI page parameter when ONFI is
 *			supported, 0 otherwise.
 * @ecclayout:		[REPLACEABLE] the default ecc placement scheme
 * @bbt:		[INTERN] bad block table pointer
 * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash
 *			lookup.
 * @bbt_md:		[REPLACEABLE] bad block table mirror descriptor
 * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial
 *			bad block scan.
 * @controller:		[REPLACEABLE] a pointer to a hardware controller
 *			structure which is shared among multiple independend
 *			devices.
 * @priv:		[OPTIONAL] pointer to private chip date
 * @errstat:		[OPTIONAL] hardware specific function to perform
 *			additional error status checks (determine if errors are
 *			correctable).
 * @write_page:		[REPLACEABLE] High-level page write function
 */

struct nand_chip {
	void __iomem *IO_ADDR_R;
	void __iomem *IO_ADDR_W;

	uint8_t (*read_byte)(struct mtd_info *mtd);
	u16  (*read_word)(struct mtd_info *mtd);
	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
	int  (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
	void (*select_chip)(struct mtd_info *mtd, int chip);
	int  (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
	int  (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
	int  (*init_size)(struct mtd_info *mtd, struct nand_chip *this, u8 *id_data);
	int  (*dev_ready)(struct mtd_info *mtd);
	void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
	int  (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
	void (*erase_cmd)(struct mtd_info *mtd, int page);
	int  (*scan_bbt)(struct mtd_info *mtd);
	int  (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
	int  (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw);

	int chip_delay;
	unsigned int options;

	int page_shift;
	int phys_erase_shift;
	int bbt_erase_shift;
	int chip_shift;
	int numchips;
	uint64_t chipsize;
	int pagemask;
	int pagebuf;
	int subpagesize;
	uint8_t cellinfo;
	int badblockpos;
	int badblockbits;

	int onfi_version;
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
	struct nand_onfi_params onfi_params;
#endif

	int state;

	uint8_t *oob_poi;
	struct nand_hw_control *controller;
	struct nand_ecclayout *ecclayout;

	struct nand_ecc_ctrl ecc;
	struct nand_buffers *buffers;
	struct nand_hw_control hwcontrol;

	struct mtd_oob_ops ops;

	uint8_t *bbt;
	struct nand_bbt_descr *bbt_td;
	struct nand_bbt_descr *bbt_md;

	struct nand_bbt_descr *badblock_pattern;

	void *priv;
};

三、uboot nand部分初始化流程

nand_init();  
    nand_init_chip()  
        board_nand_init()  
        //主要是初始化 struct nand_chip结构体以及struct nand_chip结构体struct nand_ecc_ctrl ecc成员中的方法,两个结构体中的方法如果通过自己实现; 
        一般在这里实现;并用自己实现的函数初始化struct nand_chip结构体; 没有初始化的成员在后面会初始成默认的函数。
        这些都是操作nand的底层函数,具体可以看上面的结构体描述
          
        nand_scan()  
            nand_scan_ident()  
		nand_set_defaults(chip, busw);  
                //如果前面没有初始化 struct nand_chip结构体,在这里把struct nand_chip结构体初始成默认的函数  
                nand_scan_tail()  
                //初始化struct mtd_info 结构体,特别是成员struct nand_ecc_ctrl ecc,如果前面没有初始化,在这里把struct nand_ecc_ctrl结构体初始成默认的函数 ;  
                 并且会根据是否硬件ECC还是软件ECC来对ecc初始不同的函数 
                 
PS:其中mtd_info 结构体包含了struct nand_chip结构体的指针;对struct nand_ecc_ctrl ecc的初始的地方有两处,
一处是:board_nand_init() 另一处是: nand_scan_tail(),如果board_nand_init()没有初始,就会在nand_scan_tail() 中使用默认的,
初始化完这些结构体后,就可以操作硬件了。

四、命令nand read / write调用流程  
U_BOOT_CMD(  
    nand, CONFIG_SYS_MAXARGS, 1, do_nand,  
    "NAND sub-system", nand_help_text  
);  

-->do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  
    -->nand_read_skip_bad(nand, off, &rwsize, (u_char *)addr);  
        -->nand_read(nand, offset, length, buffer);  
            -->info->read(info, ofs, *len, (size_t *)len, buf);  //这里只用read来分析,其它都相似
            //这里的info就是mtd_info结构体{typedef struct mtd_info nand_info_t;} 
            
从前面初始化struct mtd_info 结构体可知:info->read被初始化成了nand_read;  
nand_scan_tail()              
mtd->read = nand_read;  
  
nand_read();  
    -->nand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);  
        struct nand_chip *chip = mtd->priv;  
        chip->select_chip(mtd, chipnr);  
        while (1) {  
            chip->ecc.read_page(mtd, chip, bufpoi, page);  
            //这个就是我们前面在nand_scan_tail()中初始化的struct mtd_info 结构体中的ecc成员  
        }  
  
  
假如我们是硬件ECC,那么就有:  
  
chip->ecc.read_page(mtd, chip, bufpoi, page) = nand_read_page_hwecc;
nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page)
	-->chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  
        //这里调用了我们前面初始化的nand_chip结构体中的方法;  
        
假如我们是软件ECC,那么就有:
  
chip->ecc.read_page(mtd, chip, bufpoi, page) = nand_read_page_swecc;  
nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) 
	-->chip->ecc.read_page_raw(mtd, chip, buf, page);  
	//这里调用了我们前面初始化的nand_chip结构体中的struct nand_ecc_ctrl ecc成员中的方法;
	
	
nand write调用流程和这类似
过程大概就是这样,对照源码看比较容易明白。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值