参考:
omapl138移植uboot系列之添加MTD分区(第七篇)_uboot增加分区_明故宫的记忆的博客-CSDN博客
问题:
(1)uboot支持nor flash sf命令后,如何与网络配置进行版本更新?
(2)uboot如何支持MTD设备,Nor flash MTD分区如何进行分区划分?
(3)uboot中的分区如何与kernel中的分区进行统一?
(4)uboot变量mtdparts=60000000.nor:2m@0x100000(nor_bank0_uboot),40m@0x1100000(nor_bank0_fit),7m(nor_bank0_user),2m@0x4100000(nor_bank4_uboot),40m@0x5100000(nor_bank4_fit),-(nor_bank4_user);
对于uboot如何起作用的?对于kernel又是怎么起作用的
(5)mtd命令支持
1 相关配置宏
(1)CONFIG_SPI_FLASH_MTD=y
依赖于:
CONFIG_SPI_FLASH=y
CONFIG_MTD=y
(2)CONFIG_MTD_NOR_FLASH //支持多个nor flash会用到?
2 概述
MTD(memory Teachno Device)中文翻译为“内存技术设备”,是Linux系统对“NorFlash”,“NandFlash”等存储设备抽象出来的一个设备层,它向上提供统一的访问接口,屏蔽底层硬件的操作,而uboot中分区只是为了方便操作。
例如,我想将SPI Flash地址0x00010000处偏移量为1M的数据加载到内存地址0xC2000000处,一般情况,我们都是这样写:
sf read 0xC2000000 0x00010000 100000
但如果有了uboot的分区,我们可以写
sf read 0xC2000000 uboot
一言以蔽之“uboot中的mtd分区只是代码的一种手段,方便我们使用,用名字代替一些数字”
2.1 uboot支持MTD分区
在spi_flash_std_probe函数中,会调用spi_flash_probe_slave函数,在CONFIG_SPI_FLASH_MTD宏打开的情况下,会调用到spi_flash_mtd_register将spi_flash注册为MTD设备。函数的具体实现如下:
int spi_flash_mtd_register(struct spi_flash *flash)
{
int ret;
if (sf_mtd_registered) {
ret = del_mtd_device(&sf_mtd_info); //如果已经注册,先删除MTD设备
if (ret)
return ret;
sf_mtd_registered = false;
}
sf_mtd_registered = false;
memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
//初始化MTD设备相关的信息
sf_mtd_info.name = sf_mtd_name;
sf_mtd_info.type = MTD_NORFLASH;
sf_mtd_info.flags = MTD_CAP_NORFLASH;
sf_mtd_info.writesize = 1;
sf_mtd_info.writebufsize = flash->page_size;
//mtd nor flash操作过程中使用的函数
sf_mtd_info._erase = spi_flash_mtd_erase;
sf_mtd_info._read = spi_flash_mtd_read;
sf_mtd_info._write = spi_flash_mtd_write;
sf_mtd_info._sync = spi_flash_mtd_sync;
sf_mtd_info.size = flash->size;
sf_mtd_info.priv = flash;
/* Only uniform flash devices for now */
sf_mtd_info.numeraseregions = 0;
sf_mtd_info.erasesize = flash->sector_size;
ret = add_mtd_device(&sf_mtd_info); //注册MTD设备,为什么不用add_mtd_partitions(&sf_mtd_info,mapl138_spiflash_partition,1);
if (!ret)
sf_mtd_registered = true;
return ret;
}
下面先具体函数add_mtd_device,没看明白
int add_mtd_device(struct mtd_info *mtd)
>>> i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
>>> mtd->index = i;
>>> mtd->usecount = 0;
>>> mtd->bitflip_threshold = mtd->ecc_strength;
>>> mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
>>> mtd->writesize_shift = ffs(mtd->writesize) - 1;
>>> mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
>>> mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
2.2 添加环境变量
对于u-boot而言,设置了mtdparts变量之后,可以在sf read/write/erase命令中直接使用分区的名字而不必指定分区的偏移位置。
将上面的宏打开之后,spi flash便添加到MTD,我们就可以根据需要,对spi flash进行分区。
SpiFlash地址 分区名 分区大小
0x0000_0000 ~ 0x0000_FFFF uboot_spl 64K
0x0001_0000 ~ 0x0008_FFFF uboot 512K
0x0009_0000 ~ 0x0009_FFFF Env 64K
0x0010_0000 ~ 0x003F_0000 Kernel 3M
0x0040_0000 ~ 0x004F_FFFF arm_app 1M
0x0050_0000 ~ 0x005F_FFFF dsp_app 1M
剩下所有余量 rootfs
不必修改代码,只要修改两个环境变量即可完成上述分区,uboot命令行下按照顺序输入下图红线标识的命令
set mtdids nor0=639b_nor0
set mtdparts mtdparts=639b_nor0:64k@0(spl),512k@64k(uboot),64k@576k(env),3m@1m(kernel),1m@4m(arm_app),1m@5m(dsp_ubl),1m@6m(dsp_app),3m@7m(rootfs)
首先解释下mtdids环境变量,该变量注册了一块MTD设备,该设备是norflash类型,编号为0,该MTD设备命名为“639b_nor0”。
mtdids是对整块Flash设备进行MTD描述,那么mtdparts就是对这块MTD设备进行分区描述了,以上设置的意思是:以SPIFlash 0x0地址为参考,从第0K开始连续64k空间命名为“spl”分区,从第64K开始连续512K空间命名为“uboot”分区,从第576K开始连续64K空间命名为“env”分区,从第1M开始连续3M空间命名为“kernel”分区,从第4M开始连续1M空间命名为“arm_app”分区,从第5M开始连续1M空间命名为“dsp_ubl”分区,从第6M开始连续1M空间命名为“arm_app”分区, ,从第7M开始连续3M空间命名为“rootfs”分区。
uboot命令行下,输入“mtd”命令,分区显示如下
需要说明的是,如果想要在命令行交互界面使用mtd命令,需要将相关的cmd使能,需要将下面的宏打开
CONFIG_CMD_MTD=y
CONFIG_SYS_LONGHELP=y
当打开CONFIG_CMD_MTD这个宏时,Kconfig会自动的select CONFIG_MTD_PARTITIONS=y。而这2个最终会编译mtd.c及mtdparts.c 两个文件。
cmd/Makefile:105:obj-$(CONFIG_CMD_MTD) += mtd.o
cmd/Makefile:106:obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
首先看下mtd命令
文件:mtd.c
static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
>>> mtd_probe_devices();
>>> const char *mtdparts = get_mtdparts(); //获取mtdparts分区信息
>>> mtdparts = env_get("mtdparts"); //若环境变量中有mtdparts分区信息,直接返回此信息
>>> mtdparts = MTDPARTS_DEFAULT; //从板级的configs/*.h中获取
>>> mtdparts = CONFIG_MTDPARTS_DEFAULT; //从默认的配置选项中获取
>>> env_set("mtdparts", mtdparts); //设置到环境变量
>>> const char *mtdids = get_mtdids(); //获取mtdids信息
>>> mtd = get_mtd_device_nm(mtd_name); //通过nor flash的名称获取mtd设备句柄,这个设备是在spi_flash_mtd_register函数中通过调用add_mtd_device函数进行分区mtd_info信息初始化的
>>> ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts); //解析mtd分区
>>> add_mtd_partitions(mtd, parts, nparts); //创建新的mtd分区
>>> mtd_for_each_device(mtd) { // 轮询mtd设备,显示分区信息
if (!mtd_is_partition(mtd))
mtd_show_device(mtd);
}
调试完成后,可以使用启动命令
#define CONFIG_BOOTCOMMAND "sf probe 0; " \
"sf read 0x41800000 0x100000 0x10000; " \
"sf read 0x41000000 0x110000 0x400000; " \
"bootz 0x41000000 - 0x41800000"
#define CONFIG_BOOTARGS "console=ttyS0,115200 earlyprintk panic=5 rootwait " \
"mtdparts=spi32766.0:1M(uboot)ro,64k(dtb)ro,4M(kernel)ro,-(rootfs) root=31:03 rw rootfstype=jffs2"