linux下的nandflash驱动分析(3)——基于s3c6410平台

发布者:快乐阳光最新更新时间:2022-06-14 来源: eefocus关键字:linux  nandflash 手机看文章 扫描二维码
随时随地手机看文章

在上一篇中probe函数中的一个很重要的函数nand_scan函数,现在来说另外一个很重要的函数add_mtd_partitions函数,add_mtd_partitions()会对每一个新建分区建立一个新的mtd_part 结构体,将其加入mtd_ partitions中,并调用add_mtd_device()将此分区作为MTD设备加入mtd_table。成功时返回0,如果分配mtd_part时内存不足,则返回-ENOMEM。


1、在说这个函数前,先说下,与这有关的结构体struct mtd_part和struct mtd_partition结构体,如下所示:


mtd_part结构体用于描述分区,其mtd_info结构体成员用于描述本分区


/* Our partition node structure */

struct mtd_part {

struct mtd_info mtd;  分区的信息(大部分由其master决定

struct mtd_info *master;  该分区的主分区

u_int32_t offset;  该分区的偏移地址

int index;  分区号

struct list_head list;

int registered;

};


/*

 * Partition definition structure:

 *

 * An array of struct partition is passed along with a MTD object to

 * add_mtd_partitions() to create them.

 *

 * For each partition, these fields are available:

 * name: string that will be used to label the partition's MTD device.

 * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition

 * will extend to the end of the master MTD device.

 * offset: absolute starting position within the master MTD device; if

 * defined as MTDPART_OFS_APPEND, the partition will start where the

 * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.

 * mask_flags: contains flags that have to be masked (removed) from the

 * master MTD flag set for the corresponding MTD partition.

 * For example, to force a read-only partition, simply adding

 * MTD_WRITEABLE to the mask_flags will do the trick.

 *

 * Note: writeable partitions require their size and offset be

 * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).

 */



struct mtd_partition {

char *name;  /* identifier string */  标识字符串

u_int32_t size; /* partition size */   分区大小

u_int32_t offset; /* offset within the master MTD space */   主MTD空间内的偏移

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 */

};


现在来看下6410中的定义:


struct mtd_partition s3c_partition_info[] = {

        {

                .name = "Bootloader",

                .offset = 0,

                .size = (256*SZ_1K),

                .mask_flags = MTD_CAP_NANDFLASH,

        },

        {

                .name = "Kernel",

                .offset = (256*SZ_1K),

                .size = (4*SZ_1M) - (256*SZ_1K),

                .mask_flags = MTD_CAP_NANDFLASH,

        },

#if defined(CONFIG_SPLIT_ROOT_FILESYSTEM)

        {

                .name = "Rootfs",

                .offset = (4*SZ_1M),

               // .size = (512*SZ_1M),//(48*SZ_1M),

.size = (80*SZ_1M),//(48*SZ_1M),

        },

#endif

        {

                .name = "File System",

                .offset = MTDPART_OFS_APPEND,

                .size = MTDPART_SIZ_FULL,

        }

};



struct s3c_nand_mtd_info s3c_nand_mtd_part_info = {

.chip_nr = 1,

.mtd_part_nr = ARRAY_SIZE(s3c_partition_info),

.partition = s3c_partition_info,

};


2、下面来看add_mtd_partitions函数,源码如下:


/*

 * This function, given a master MTD object and a partition table, creates

 * and registers slave MTD objects which are bound to the master according to

 * the partition definitions.  

 * (Q: should we register the master MTD object as well?)

 */

int add_mtd_partitions(struct mtd_info *master,

      const struct mtd_partition *parts,

      int nbparts)

{

struct mtd_part *slave;

u_int32_t cur_offset = 0;

int i;



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



for (i = 0; i < nbparts; i++) {  主要就是这个循环体,应该是分别添加每个struct mtd_partition结构

slave = add_one_partition(master, parts + i, i, cur_offset);

if (!slave)

return -ENOMEM;

cur_offset = slave->offset + slave->mtd.size;

}



return 0;

}


接着看add_one_partition函数,源码如下:




static struct mtd_part *add_one_partition(struct mtd_info *master,

const struct mtd_partition *part, int partno,

u_int32_t cur_offset)

{

 struct mtd_part *slave; 新建的struct mtd_part结构

/* 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);


这里有个定义:static LIST_HEAD(mtd_partitions);



/* set up the MTD object for this partition */ 其实下面这么多,基本上都是根据主分区和我们定义的


struct mtd_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->point && master->unpoint) {

slave->mtd.point = part_point;

slave->mtd.unpoint = part_unpoint;

}



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 (!partno && master->suspend && master->resume) {

slave->mtd.suspend = part_suspend;

slave->mtd.resume = part_resume;

}

if (master->writev)

slave->mtd.writev = part_writev;

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->offset == MTDPART_OFS_APPEND)

slave->offset = cur_offset;

if (slave->offset == MTDPART_OFS_NXTBLK) {

slave->offset = cur_offset;

if ((cur_offset % master->erasesize) != 0) {

/* Round up to next erasesize */

slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;

printk(KERN_NOTICE "Moving partition %d: "

      "0x%08x -> 0x%08xn", partno,

      cur_offset, slave->offset);

}

}

if (slave->mtd.size == MTDPART_SIZ_FULL)

slave->mtd.size = master->size - slave->offset;



printk(KERN_NOTICE "0x%08x-0x%08x : "%s"n", slave->offset,

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 -- disabledn",

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 %#xn",

part->name, master->name, slave->mtd.size);

}

if (master->numeraseregions > 1) {

/* Deal with variable erase size stuff */

int i, max = master->numeraseregions;

u32 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) &&

   (slave->offset % slave->mtd.erasesize)) {

/* 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-onlyn",

part->name);

}

if ((slave->mtd.flags & MTD_WRITEABLE) &&

   (slave->mtd.size % slave->mtd.erasesize)) {

slave->mtd.flags &= ~MTD_WRITEABLE;

printk(KERN_WARNING"mtd: partition "%s" doesn't end on an erase block -- force read-onlyn",

[1] [2]
关键字:linux  nandflash 引用地址:linux下的nandflash驱动分析(3)——基于s3c6410平台

上一篇:s3c6410的RTC在linux中的驱动(1)
下一篇:linux串口终端驱动——s3c6410平台(四)

推荐阅读最新更新时间:2024-10-26 21:28

linux下的nandflash驱动分析(2)——基于s3c6410平台
1、在上一篇的probe函数中,在那个很大的for循环中出现了,对NAND的厂商,设备号,是MLC或SLC进行判断,这些是怎样进行的呢? 其实这些都是在NAND芯片中定义的,我们只需按对应的时序读出这些信息,就可以进行判断,看下面这个图(摘于一个NAND芯片手册): 2、上一篇中,nand_scan(s3c_mtd, 1)函数没有细说,这一篇说下这个函数,源码如下: /** * nand_scan - Scan for the NAND device * @mtd: MTD device structure * @maxchips: Number of chips to scan for * *
[单片机]
<font color='red'>linux</font>下的<font color='red'>nandflash</font>驱动分析(2)——基于<font color='red'>s3c6410</font><font color='red'>平台</font>
linux下的nandflash驱动分析(1)——基于s3c6410平台
源码主要在S3c_nand.c (linux2.6.28driversmtdnand)文件中。 1、模块加载和卸载 module_init(s3c_nand_init); module_exit(s3c_nand_exit); static void __exit s3c_nand_exit(void) { platform_driver_unregister(&s3c2450_nand_driver); platform_driver_unregister(&s3c6400_nand_driver); platform_driver_unregister(&s3c6410_nand_driver); platform
[单片机]
<font color='red'>linux</font>下的<font color='red'>nandflash</font>驱动分析(1)——基于<font color='red'>s3c6410</font><font color='red'>平台</font>
linux下的nandflash驱动分析(3)——基于s3c6410平台
在上一篇中probe函数中的一个很重要的函数nand_scan函数,现在来说另外一个很重要的函数add_mtd_partitions函数,add_mtd_partitions()会对每一个新建分区建立一个新的mtd_part 结构体,将其加入mtd_ partitions中,并调用add_mtd_device()将此分区作为MTD设备加入mtd_table。成功时返回0,如果分配mtd_part时内存不足,则返回-ENOMEM。 1、在说这个函数前,先说下,与这有关的结构体struct mtd_part和struct mtd_partition结构体,如下所示: mtd_part结构体用于描述分区,其mtd_info结构体
[单片机]
S3C6410嵌入式应用平台构建(四)——linux-3.14.4移植到OK6410-(初步启动)
这次,还是把基本的基于我目前最新的Linux源码进行移植到OK6410吧,同时也写下我移植过程中遇到的问题及解决方法,不过有些方法是借鉴网上的,有些是自己加的,会有一些小bug。 一、基本工作 1. 源码下载 https://www.kernel.org/ ,最好是下载stable版本,否则会有小bug。(我现在调试的是stable版本, linux-3.14.4) 2. 拷到自己的文件夹下解压,我下的是.xz后缀的,这样文件比较小,只是解压时多一个步骤。 $ xz –d linux-3.14.4.tar.xz $ tar xvf linux-3.14.4.tar 3. 解压完后,进入解压后的目录 二、源码
[单片机]
<font color='red'>S3C6410</font>嵌入式应用<font color='red'>平台</font>构建(四)——<font color='red'>linux</font>-3.14.4移植到OK6410-(初步启动)
S3C6410嵌入式应用平台构建(五)——linux-3.14.4移植到OK6410-(Nand分区问题)
前一篇文章,我们的Linux能后启动了,只是在识别nand时候,没有获取到时钟源,导致后面的分区没哟进行。 我们从启动的log发现: s3c24xx-nand s3c6400-nand: failed to get clock s3c24xx-nand: probe of s3c6400-nand failed with error –2 于是追踪到代码: nandflash驱动中——s3c2410.c中 /* get the clock source and enable it */ info- clk = devm_clk_get(&pdev- dev, nand ); if (IS_ERR(
[单片机]
S3C6410嵌入式应用平台构建(六)——linux-3.14.4移植到OK6410-(Yaffs2文件系统移植)
我个人觉得nandflash上用yaffs2文件系统是很好的方案,但是最新的Linux并不支持yaffs2文件系统,需要你自己给内核打补丁,不过话说在前面,由于内核间差异及兼容问题,在编译时肯定会出现各种编译问题,需要你一一的去解决。 一、准备工作 1. 下载源码 使用git工具下载:$ git clone git://www.aleph1.co.uk/yaffs2 2. 给内核打补丁 下载完成后,在该执行目录下会有yaffs2文件夹,进入该文件夹。 $ ./patch-ker.sh c m ../../kernel/test/linux-3.14.4 Updating ../../kernel/te
[单片机]
<font color='red'>S3C6410</font>嵌入式应用<font color='red'>平台</font>构建(六)——<font color='red'>linux</font>-3.14.4移植到OK6410-(Yaffs2文件系统移植)
S3C6410嵌入式应用平台构建(六)——linux-3.14.4移植到OK6410-(Yaffs2文件制作)
本文主要讲怎用利用yaffs2工具和busybox制作yaffs2文件系统镜像。大多数都是参照网上的,目的在于记录学习,不做任何用途。 一、制作mkyaffs2image工具 进入yaffs2源码目录下utils目录,修改mkyaff2image.c,做如下修改: // Adjust these to match your NAND LAYOUT: #if 0 #define chunkSize 2048 #define spareSize 64 #define pagesPerBlock 64 #else #define chunkSize 4096 #define spareSize 218 #defin
[单片机]
linux串口终端ttySAC,Linux串口终端驱动——S3C6410平台
1、serial文件夹下Kconfig分析 config SERIAL_SAMSUNG tristate Samsung SoC serial support depends on ARM && PLAT_S3C select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,为支持三星的片上UARTs控制器 providing /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of these ports, depending on how
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved