这几天在做和nandflash相关的东西,之前uboot中nandflash部分搞得模模糊糊。这次就将uboot中nand flash相关部分分析清楚
。本文uboot版本1.3.3
初始化的调用流程大致为:
start_armboot
nand_init
//driver/mtd/nand/nand.c
nand_init_chip //driver/mtd/nand/nand.c
board_nand_init
//cpu/sep4020/nand_flash.c
nand_scan //driver/mtd/nand/nand_base.c
start_armboot函数中,nand初始化部分
点击(此处)折叠或打开
- void nand_init(void)
-
{
-
int i;
- unsigned int size = 0;
-
for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { //(1)
- nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]); //(2)
- size += nand_info[i].size; //(3)
-
if (nand_curr_device == -1)
- nand_curr_device = i;
-
}
- printf("%lu MiB\n", size / (1024 * 1024));
- #ifdef CFG_NAND_SELECT_DEVICE
-
/*
-
* Select the chip in the board/cpu specific driver
-
*/
- board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
- #endif
- }
参数1 nand_info[i],其定义如
nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
//driver/mtd/nand/nand.c
typedef struct mtd_info nand_info_t; //include/Nand.h
点击(此处)折叠或打开
- struct mtd_info {
- u_char type;
- u_int32_t flags;
- u_int32_t size; /* Total size of the MTD */
-
/* "Major" erase size for the device. Na飗e 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;
- u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */
- u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
- u_int32_t oobavail; /* Number of bytes in OOB area available for fs */
- u_int32_t ecctype;
- u_int32_t eccsize;
-
/* Kernel-only stuff starts here. */
- char *name;
-
int index;
-
/* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSetoOBINFO) */
- struct nand_oobinfo oobinfo;
-
/* 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;
-
/* This really shouldn't be here. It can go away in 2.5 */
- u_int32_t bank_size;
-
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-
/* This stuff for eXecute-In-Place */
-
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
-
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
- void (*unpoint) (struct mtd_info *mtd, u_char * addr, size_t len);
-
int (*read) (struct mtd_info *mtd, u_char *buf);
-
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-
int (*read_ecc) (struct mtd_info *mtd, u_char *buf, u_char
-
*eccbuf, struct nand_oobinfo *oobsel);
-
int (*write_ecc) (struct mtd_info *mtd, const u_char *buf, struct nand_oobinfo *oobsel);
-
int (*read_oob) (struct mtd_info *mtd, u_char *buf);
-
int (*write_oob) (struct mtd_info *mtd, const u_char *buf);
-
/*
-
* 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 (*read_user_prot_reg) (struct mtd_info *mtd, u_char *buf);
-
int (*read_fact_prot_reg) (struct mtd_info *mtd, u_char *buf);
-
/* This function is not yet implemented */
-
int (*write_user_prot_reg) (struct mtd_info *mtd, u_char *buf);
-
/* Sync */
- void (*sync) (struct mtd_info *mtd);
-
/* Bad block management functions */
-
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
-
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
- void *priv;
- struct module *owner;
-
int usecount;
- };
参数2 nand_chip[i] ,如下
static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];
再看struct nand_chip定义,当前文件(driver/mtd/nand/nand.c)包含nand.h(include目录),nand.h又包含#include <linux/mtd/nand.h>,所以nand_chip的定义是linux/mtd/nand.h中的。不是nand_legacy.h。这个结构体表示一个nand flash其包含所有属性和操作函数。
点击(此处)折叠或打开
-
/**
-
* 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
-
* @write_byte: [REPLACEABLE] write one byte to the chip
-
* @read_word: [REPLACEABLE] read one word from the chip
-
* @write_word: [REPLACEABLE] write one word to 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
-
* @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
-
* @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
-
* @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
-
* @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
-
* @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
-
* be provided if a hardware ECC is available
-
* @erase_cmd: [INTERN] erase command write function, selectable due to AND support
-
* @scan_bbt: [REPLACEABLE] function to scan bad block table
-
* @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
-
* @eccsize: [INTERN] databytes used per ecc-calculation
-
* @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
-
* @eccsteps: [INTERN] number of ecc calculation steps per page
-
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
-
* @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
-
* @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
-
* @state: [INTERN] the current state of the NAND device
-
* @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
-
* @data_buf: [INTERN] internal buffer for one page + oob
-
* @oob_buf: [INTERN] oob buffer for one eraseblock
-
* @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
-
* @data_poi: [INTERN] pointer to a data buffer
-
* @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
-
* @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
-
* @autooob: [REPLACEABLE] the default (auto)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: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
-
* @priv: [OPTIONAL] pointer to private chip date
-
*/
- struct nand_chip {
- void __iomem *IO_ADDR_R;
- void __iomem *IO_ADDR_W;
- u_char (*read_byte)(struct mtd_info *mtd);
- void (*write_byte)(struct mtd_info *mtd, u_char byte);
- u16 (*read_word)(struct mtd_info *mtd);
- void (*write_word)(struct mtd_info *mtd, u16 word);
- void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
- void (*read_buf)(struct mtd_info *mtd, int len);
-
int (*verify_buf)(struct mtd_info *mtd, 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 (*hwcontrol)(struct mtd_info *mtd, int cmd);
-
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, int state);
-
int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
-
int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
- void (*enable_hwecc)(struct mtd_info *mtd, int mode);
- void (*erase_cmd)(struct mtd_info *mtd, int page);
-
int (*scan_bbt)(struct mtd_info *mtd);
-
int eccmode;
-
int eccsize;
-
int eccbytes;
-
int eccsteps;
-
int chip_delay;
- #if 0
- spinlock_t chip_lock;
- wait_queue_head_t wq;
- nand_state_t state;
- #endif
-
int page_shift;
-
int phys_erase_shift;
-
int bbt_erase_shift;
-
int chip_shift;
- u_char *data_buf;
- u_char *oob_buf;
-
int oobdirty;
- u_char *data_poi;
- unsigned int options;
-
int badblockpos;
-
int numchips;
- unsigned long chipsize;
-
int pagemask;
-
int pagebuf;
- struct nand_oobinfo *autooob;
- uint8_t *bbt;
- struct nand_bbt_descr *bbt_td;
- struct nand_bbt_descr *bbt_md;
- struct nand_bbt_descr *badblock_pattern;
- struct nand_hw_control *controller;
- void *priv;
- };
参数3 base_address[i],如下
static ulong base_address[CFG_MAX_NAND_DEVICE] = CFG_NAND_BASE_LIST;
CFG_NAND_BASE_LIST如下,
#ifndef CFG_NAND_BASE_LIST
#define CFG_NAND_BASE_LIST { CFG_NAND_BASE }
#endif
CFG_NAND_BASE是在include/configs/UB4020.h中配置为
#define CFG_NAND_BASE
0x11000200 (nand FIFO 数据寄存器)
(3)计算出总共nandflash多少容量,在紧随其后的printf语句中打印出来。
点击(此处)折叠或打开
- static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr)
-
{
- mtd->priv = nand;
- nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; //(1)
-
if (board_nand_init(nand) == 0) { //(2)
-
if (nand_scan(mtd, 1) == 0) { //(3)
-
if (!mtd->name) //这个名字在nand_scan中设置,如果在table中找到就有了。
- mtd->name = (char *)default_nand_name;
-
} else
- mtd->name = NULL;
-
} else {
- mtd->name = NULL;
- mtd->size = 0;
-
}
- }
(1)从上面的nand_chip结构体中写道IO_ADDR_R,IO_ADDR_W是nand flash的读写地址, base_add这里设置为0x11000200,正好的nand FIFO的数据寄存器,读写flash的接口寄存器。
点击(此处)折叠或打开
-
int board_nand_init( struct nand_chip *chip )
-
{
- memset((char *) chip, 0, sizeof(struct nand_chip));
- INTC_IMR = 0XFFFFFFFF; //(REGW(INTC_BASE+0X008))IRQ中断屏蔽寄存器 置1为屏蔽 0为通过
- INTC_IMR = 0X00000000;
- EMI_NAND_CONF1 = 0x06402857; //(1)
- EMI_NAND_CONF2 = 0x00d14353; //(2)
- vaddr = malloc(2112); //(3)
- oob64 = malloc(2112);
- memset(vaddr,0,2112);
- memset(oob64,2112);
-
int erasepage;
-
/*设置nand_chip结构中的各个函数指针*/
-
/* Set address of NAND IO lines */
- chip->IO_ADDR_R = (void *) EMI_NAND_DATA_RAW; //设置nand flash读写寄存器地址,其实在调用函数中已经设置过了
- chip->IO_ADDR_W = (void *) EMI_NAND_DATA_RAW;
-
/* Set address of hardware control function */
- chip->hwcontrol = sep4020_hwcontrol;
-
/* 15 us command delay time */
- chip->dev_ready = sep4020_nand_dev_ready;
- chip->chip_delay = 15;
- chip->write_buf = sep4020_nand_write_buf;
- chip->read_buf = sep4020_nand_read_buf;
- chip->write_byte = sep4020_nand_write_byte;
- chip->read_byte = sep4020_nand_read_byte;
- chip->eccmode = NAND_ECC_SOFT;
- chip->select_chip = sep4020_nand_select_chip;
- chip->cmdfunc = sep4020_nand_command;
- chip->erase_cmd = sep4020_nand_cmd_erase;
-
/* Return happy */
- return 0;
- }
(1)NAND FLASH的配置器存器1 110-0--100--000000--101000--0101--0111 可查看芯片手册,其中一项设置成5级地址
(2)NAND FLASH的配置器存器2 1--1--0--100--010100--0011--01--01--00--11 可查看芯片手册,页大小配置为2K
(3)分配一个整页空间,后续的读写操作中会用到它来暂存一页数据。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。