//S3C2440's NAND flash registers struct s3c2440_nand { unsigned int nfconf; //set time for different nand flash unsigned int nfcont; //nand flash control register unsigned int nfcmmd; //nand flash commond set register unsigned int nfaddr; //nand flash address set register unsigned int nfdata; //nand flash data recive register unsigned int nfmeccd0; //nand flash ecc 1st and 2nd register for main data read unsigned int nfmeccd1; //nand flash ecc 3nd and 4th register for main data read unsigned int nfseccd; //nand flash ecc register for spare area data read unsigned int nfstat; //nand flash operation status register unsigned int nfstat0; //nand flash ecc status register for io[7:0] unsigned int nfstat1; //nand flash ecc status register for io[15:8] unsigned int nfmecc0; //nand flash ecc status register for data[7:0] unsigned int nfmecc1; //nand flash ecc status register for data[15:8] unsigned int nfsecc; //nand flash ecc register for io[15:0] unsigned int nfsblk; //nand flash programmable start block address unsigned int nfeblk; //nand flash programmable end block address }; /* NAND Flash上面的分区大小以及个数 */ static struct mtd_partition nand_driver_parts[] = { [0] = { .name = "bootloader", .size = 0x00040000, .offset = 0, }, [1] = { .name = "params", .offset = MTDPART_OFS_APPEND, .size = 0x00020000, }, [2] = { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = 0x00200000, }, [3] = { .name = "root", .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, } }; /* 各种结构体 */ static struct nand_chip *nand_driver_chip; static struct mtd_info *nand_driver_mtdinfo; static struct s3c2440_nand *s3c_nand_regs; static struct clk *nand_clk; /* NAND Flash的命令控制 */ static void nand_driver_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { if(ctrl == NAND_CMD_NONE) //空命令 return; if(ctrl & NAND_ALE) //发地址命令 { s3c_nand_regs->nfaddr = cmd; //发地址 } else if(ctrl & NAND_CLE) //发命令 { s3c_nand_regs->nfcmmd = cmd; //发命令 } } /* 判断设备是否准备好 */ int nand_device_ready(struct mtd_info *mtd) { return (s3c_nand_regs->nfstat & (1 << 0)); } /* 是否选中芯片 */ void nand_device_select(struct mtd_info *mtd, int chip) { if(chip == -1) { /* 取消选中 */ s3c_nand_regs->nfcont |= (1 << 1); } else { /* 选中芯片 */ s3c_nand_regs->nfcont &= ~(1 << 1); } } /* 驱动模块的初始化 */ static int nand_driver_init(void) { /* 分配一个nand_chip结构体 */ nand_driver_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); /* 映射S3C2440的IO资源 */ s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c2440_nand)); /* 设置nand flash的读写地址 */ nand_driver_chip->IO_ADDR_R = &s3c_nand_regs->nfdata; nand_driver_chip->IO_ADDR_W = &s3c_nand_regs->nfdata; /* nand flash的命令控制: 命令使能或者地址使能 */ nand_driver_chip->cmd_ctrl = nand_driver_cmd_ctrl; /* nand flash设备是否准备好 */ nand_driver_chip->dev_ready = nand_device_ready; /* 使能ECC校验,nand flash容易产生位翻转 */ nand_driver_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ nand_driver_chip->chip_delay = 20; /* 20us command delay time */ /* 使能nand flash芯片 */ nand_driver_chip->select_chip = nand_device_select; /* 硬件相关的设置 */ nand_clk = clk_get(NULL, "nand"); //得到nand的时钟控制位 clk_enable(nand_clk); //使能时钟 /* 使能nand控制器,初始化取消片选 */ s3c_nand_regs->nfcont |= (1 << 0) | (1 << 1); /* 设置时间参数 */ s3c_nand_regs->nfconf |= (0 << 12) | (1 << 8) | (0 << 4); /* 分配mtd_info结构体 */ nand_driver_mtdinfo = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); /* mtd结构体的拥有者,模块句柄 */ nand_driver_mtdinfo->owner = THIS_MODULE; nand_driver_mtdinfo->priv = nand_driver_chip; /* 扫描nand,对mtd结构体进行填充,只有一块芯片 */ nand_scan(nand_driver_mtdinfo, 1); /* 添加分区,4个分区 */ <span style="white-space: pre;"> </span>add_mtd_partitions(nand_driver_mtdinfo, nand_driver_parts, 4); <span style="white-space: pre;"> </span>return 0; } /* 驱动模块的卸载 */ static void nand_drier_exit(void) { del_mtd_partitions(nand_driver_mtdinfo); kfree(nand_driver_mtdinfo); kfree(nand_driver_chip); iounmap(s3c_nand_regs); } module_init(nand_driver_init); module_exit(nand_drier_exit); MODULE_LICENSE("GPL");
struct nand_chip - NAND Private Flash Chip Data IO_ADDR_R: [取决于芯片]读的地址 IO_ADDR_W: [取决于芯片]写的地址 read_byte: 读一个字节 read_word: 读一个字 write_buf: 从缓冲区向flash写字串 read_buf: 从flash读取字串到缓冲区 verify_buf: 校验字串 select_chip: <span style="white-space:pre"> </span>选中芯片 block_bad: block坏块 block_markbad: <span style="white-space:pre"> </span>标记坏块 cmd_ctrl: 命令控制 ALE/CLE/nCE. Also used to write command and address //命令种类 dev_ready: 设备检测忙 If set to NULL no access to ready/busy is available and the ready/busy information is read from the chip status register cmdfunc: 特定硬件写命令函数 waitfunc: 特定硬件等待空闲函数 ecc: <span style="white-space:pre"> </span>ECC控制结构体 buffers: 读写缓冲区结构体 hwcontrol: 特定平台硬件控制结构体 ops: <span style="white-space:pre"> </span>Out of bank 数量 erase_cmd: 擦除命令 scan_bbt: 扫描坏块函数 chip_delay: 传输延时 wq: 等待队列休眠 state: <span style="white-space:pre"> </span>Flash状态 oob_poi: 坏值 page_shift: 一页的地址位数 phys_erase_shift: 物理擦除地址位数 bbt_erase_shift: 坏块地址位数 chip_shift: flash芯片上地址线位数
nand_scan nand_scan_ident nand_chip *chip = mtd->priv; //需要将mtd_info的私有结构体成员指向nand_chip结构体 nand_set_defaults //设置默认的操作函数 此函数扫描完毕之后会返回一个mtd_info结构体,结构体里面包含芯片id大小位宽等等信息
add_mtd_partitions(nand_driver_mtdinfo, nand_driver_parts, 4); for (i = 0; i < nbparts; i++) { /* 分配mtd_info结构体 */ slave = kzalloc (sizeof(*slave), GFP_KERNEL); if (!slave) { printk ("memory allocation error while creating partitions for \"%s\"\n", master->name); del_mtd_partitions(master); return -ENOMEM; } list_add(&slave->list, &mtd_partitions); 。。。 加入链表之后对结构体进行设置, add_mtd_device(&slave->mtd); //此处添加mtd设备 }