转载_linux中at91rm9200板子nor flash驱动添加及心得
linux2.6.20 关于mtd驱动的一些东西: 驱动必须调用register_mtd_chip_driver(struct mtd_chip_driver *drv) 将自己的驱动注册到驱动列表chip_drvs_list中,这样在接下来physmap_flash_probe--> do_map_probe-->get_mtd_chip_drive
·
linux 2.6.20
关于mtd驱动的一些东西:
驱动必须调用register_mtd_chip_driver(struct mtd_chip_driver *drv)
将自己的驱动注册到驱动列表chip_drvs_list中,这样在接下来physmap_flash_probe-->
do_map_probe-->get_mtd_chip_driver中才能返回正确的struct mtd_chip_driver类型值,
才能在do_map_probe中的drv->probe中调用正确的probe函数
SST39VF6401B的ID是0x236d,而datasheet上说的是0x236b
因为读的话是和ram一样的,写和擦的话因为符合cfi或者jedec规范,因此内核应该自己
就实现了,不需要自己实验.
/*
摘自网上
* nor flash的MTD驱动中,驱动作者需要定义自己的map_info结构体,并且为read/write
* 函数分量赋值。在write函数的实现中,大多使用__raw_writew来实现。但是向
* nor flash写入数据是要经过program的过程的,不能像写内存一样写入。而且nor flash
* 的底层读写函数实际上是在cfi_cmdset_0001/2.c中实现的,并且被赋给mtd_info的
* read/write分量。
*/
因为在启动linux的时候,从启动信息中发现了nor flash并没有被检测到,说明linux里面
并没有对这个块at91rm9200的板子进行nor flash的驱动进行移植。因此,以下为我浏览内
核中的nor flash中的一些心得。整个过程一直prink,然后编译内核......
1,首先,根据板子上的nor flash 芯片SST39VF6401B来配置好board-dk.c里面的相应的宏,
#define DK_FLASH_BASE AT91_CHIPSELECT_0
#define DK_FLASH_SIZE 0x800000 //8MB的flash
可以在这个文件看到定义的 struct resource dk_flash_resource,表明了nor flash在
内核里的设备资源结构体;struct physmap_flash_data dk_flash_data,表明了这里是
将nor flash看成physmap_flash来对待的,与nand flash不同,nand_flash的被当成了
struct at91_nand_data __initdata dk_nand_data,该结构体传递给
at91rm9200_devices.c中的at91_add_device_nand()作为参数,放在了 struct
platform_device at91rm9200_nand_device结构体中,而nor flash的 platform_device
的相应的变量定义在board-dk.c中,为 struct platform_device dk_flash,该结构体
包括了resource结构体(设备资源)、name(设备名字)和platform_data = dk_flash_data
(类型为 struct physmap_flash,为nor flash的一个配置)。
2,接着在board-dk.c里面的板子初始化函数里面就调用了
platform_device_register(&dk_flash); 将该设备的platform_device结构体添加到了内
核的设备列表中了;
3,nor flash在内核中的驱动有两种,一个是cfi_chipdrv,一个是jedec_chipdrv。两种驱动
在我的配置中都在系统时加载了,分别可以在 drivers/mtd/chips/cfi_probe.c 中的
int __init cfi_probe_init()和drivers/mtd/chips/jedec_probe.c 中的
int __init jedec_probe_init()中发现,都调用了
register_mtd_chip_driver(struct mtd_chip_driver *) 在内核中注册了这两个驱动。
4,而真正与nor flash的platform_device对应的platform_driver是定义在
drivers/mtd/maps/physmap.c中,为 struct platform_driver physmap_flash_driver。
该结构体中定义了驱动的名字(name),该变量应该与先前已经通过调用
platform_device_register()注册到内核设备列表中的nor flash设备的那个
struct platform_device dk_flash中的名字一样,这样physmap驱动才能在内核设备列表
中找到相应的设备以获得设备的资源等信息;同时该结构体中有定义了probe函数,该函数
会在platform_driver_register()中被调用,来侦测硬件设备。该驱动在系统启动时被加
载,驱动模块的初始化函数为 int __init physmap_init(),该函数中调用
platform_driver_register(struct platform_drier *)来注册驱动。
5,在 platform_driver_register()注册过程中,会调用参数结构体中的probe函数来侦测
硬件设备,这里为physmap.c中的
int physmap_flash_probe(struct platform_device *dev),其中函数的参数为在该
probe函数被调用前,在platform_driver_register()中通过platform_driver结构体中的
name变量与内核设备列表中已注册了的platform_device的结构体中的name进行匹配,从
而得到的platfor_device。因此,如果platform_device和platform_driver中的name不
一致的话,驱动是不会可能加载成功的。
6,在驱动的侦测函数physmap_flash_probe()中,比较重要的结构体为physmap_flash_info
结构体和physmap_flash_data结构体。其中physmap_flash_info中包含了很重要的信息,
包括了: struct mtd_info *, struct map_info, struct resource,如果有分区的话,
还有 struct mtd_partition *。首先先根据得到的platform_device结构体,将设备
硬件信息设置到驱动结构体中去,即初始化physmap_flash_info中的各个成员。然后,
调用 do_map_probe(char *name, struct map_info *map)来进行实质性的侦测。其中的
参数 name 来自physmap.c中的字符串数组 char *rom_probe_types[]; 这里有三个成员,
表示三种类型的nor flash,分别为"cfi_probe", "jedec_probe"和"map_rom",数组以
NULL表示结束。其实已经知道我们的nor flash SST39VF6401B为jedec类型的了,那么
接下来就直接讲解jedec类型的侦测了,虽然前面有进行了cfi类型的侦测。另一个参数
struct map_info *map则是此前根据硬件信息初始化好的结构体,该结构体在mtd体系
中扮演着十分重要的角色。
7,do_map_probe()定义在drivers/mtd/chips/chipreg.c中,看名字有知道是和芯片注册
相关的一个函数。该函数中有两个主要的结构体: struct mtd_chip_driver *,
struct mtd_info *,都是mtd体系中的重要角色。首先,函数调用get_mtd_chip_driver
函数来取得mtd_chip_driver的指针,而name参数则是上面rom_probe_types中的成员,
这里就以"jedec_probe"来说明。其实和platform_device和platform_driver这中
platform系的驱动一样,也是通过name匹配来找到彼此的。这里就通过"jedec_probe"
这个名字找到了mtd_chip_driver类型的驱动。而这个驱动是在"3"中说明了的,已经在
系统启动时已经通过调用register_mtd_chip_driver()在内核中注册好了的
jedec_chipdrv。
8,在得到了jedec_chipdrv这个驱动结构体指针之后,随即调用该驱动的probe函数,这个
probe函数定义了driver/mtd/chips/jedec_probe.c中,为
struct mtd_info *jedec_probe(struct map_info *map),这个是在驱动结构体里的
probe变量中指定了的。这个函数很干脆,直接就调用了.../gen_probe.c中定义的通
用的侦测函数 struct mtd_info *mtd_do_chip_probe(struct map_info *map,
struct chip_probe *cp),至于原因,注释上说了。
9,在通用的mtd_do_chip_probe()中,有一个比较重要的结构体 struct cfi_private *cfi,
这个结构体在后面的具体的侦测中有用。该函数为了分配这个结构体首先调用
struct cfi_private *genprobe_ident_chips(struct map_info *map,
struct chip_probe *cp),genprobe_ident_chips()中调用
int genprobe_new_chip(struct map_info *, struct chip_probe *,
struct cfi_private *);该函数为了配置cfi,又调用了 struct chip_probe *cp的成员
probe_chip来真正的侦测芯片,看看软件内的配置是否与硬件上的配置一致。这个
struct chip_probe *cp呢,又是在遥远的jedec_probe()函数中被传进来的参数
jedec_chip_probe的指针,参看"8"。这个结构体定义在jedec_probe.c中,结构体的
probe_chip成员指定给了 int jedec_probe_chip(struct map_info *, __u32,
unsigned long *, struct cfi_private *);
10,这个jedec_probe_chip()函数就以符合jedec规格的侦测方法来侦测硬件了。
其中base参数为nor flash的基地址,为0。首先是通过函数cfi_send_gen_cmd()将查询
software ID的Data 和 Addr传输给flash,然后通过jedec_read_mfr()和
jedec_read_id()取得了芯片的制造商代号和芯片id。然后调用jedec_match()测试是否
与已有的芯片符合。这个"已有的芯片"指的是该文件内定义的超长的数组
struct amd_flash_info jedec_table[]。该数组的类型结构体定义了各个制造商的各种
芯片。(唉,AMD和Intel就搞两个标准,烦)。因为内核源码中没有定义这个板子上用的
SST39VF6401B,所以要按照格式(有这么多呢)将参数添加进一个数组成员。如下:
}, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39VF6401,
.name = "SST 39VF6401",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA,
[1] = MTD_UADDR_0x5555_0x2AAA
},
.DevSize = SIZE_8MiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x1000, 2048)
}
同时,要在一堆的宏定义里面找到 SST的里面添上宏:
#define SST39VF6401 0x236d
这个0x236d即为芯片的id,从datasheet中可以知道,同时会在侦测中与从芯片里得到的
id进行匹配。但是datasheet看到的是0x236b,不是这个,不知道为什么。
11,在jedec_match()中将从硬件得到的mfc和id与那个巨大的数组内的各个成员进行匹配
以及进行一些测试。符合要求之后返回之后,就算找到了硬件了,之后进行的东西就是
在内核里面设置好合适的结构体了,然后玩成了physmap这个驱动的注册。完成注册后,
应该就完成了mtd系统中的相关设置(我不确定),关于后面如何使用驱动这个就暂不讲了。
plus: 在"11"里面,完成硬件侦测之后,会在gen_probe.c中调用check_cmd_set(),该函数
中再根据条件调用不同的函数来设置mtd_info结构体里的各种函数,包括read,
write, erase等成员。这里的转到了cfi_cmdset_0002.c里面的cfi_cmdset_0002()函
数,再调用cfi_amdstd_setup。
/* 可能底层的读写函数定义在map.h */
可能是inline_map_read, inline_map_write
mtd的write, read完成时序,比如cfi_amdstd_write_words,并且在该过程中调用
map的read, write完成总线送数据,比如map_read。
关于mtd驱动的一些东西:
驱动必须调用register_mtd_chip_driver(struct mtd_chip_driver *drv)
将自己的驱动注册到驱动列表chip_drvs_list中,这样在接下来physmap_flash_probe-->
do_map_probe-->get_mtd_chip_driver中才能返回正确的struct mtd_chip_driver类型值,
才能在do_map_probe中的drv->probe中调用正确的probe函数
SST39VF6401B的ID是0x236d,而datasheet上说的是0x236b
因为读的话是和ram一样的,写和擦的话因为符合cfi或者jedec规范,因此内核应该自己
就实现了,不需要自己实验.
/*
摘自网上
* nor flash的MTD驱动中,驱动作者需要定义自己的map_info结构体,并且为read/write
* 函数分量赋值。在write函数的实现中,大多使用__raw_writew来实现。但是向
* nor flash写入数据是要经过program的过程的,不能像写内存一样写入。而且nor flash
* 的底层读写函数实际上是在cfi_cmdset_0001/2.c中实现的,并且被赋给mtd_info的
* read/write分量。
*/
因为在启动linux的时候,从启动信息中发现了nor flash并没有被检测到,说明linux里面
并没有对这个块at91rm9200的板子进行nor flash的驱动进行移植。因此,以下为我浏览内
核中的nor flash中的一些心得。整个过程一直prink,然后编译内核......
1,首先,根据板子上的nor flash 芯片SST39VF6401B来配置好board-dk.c里面的相应的宏,
#define DK_FLASH_BASE AT91_CHIPSELECT_0
#define DK_FLASH_SIZE 0x800000 //8MB的flash
可以在这个文件看到定义的 struct resource dk_flash_resource,表明了nor flash在
内核里的设备资源结构体;struct physmap_flash_data dk_flash_data,表明了这里是
将nor flash看成physmap_flash来对待的,与nand flash不同,nand_flash的被当成了
struct at91_nand_data __initdata dk_nand_data,该结构体传递给
at91rm9200_devices.c中的at91_add_device_nand()作为参数,放在了 struct
platform_device at91rm9200_nand_device结构体中,而nor flash的 platform_device
的相应的变量定义在board-dk.c中,为 struct platform_device dk_flash,该结构体
包括了resource结构体(设备资源)、name(设备名字)和platform_data = dk_flash_data
(类型为 struct physmap_flash,为nor flash的一个配置)。
2,接着在board-dk.c里面的板子初始化函数里面就调用了
platform_device_register(&dk_flash); 将该设备的platform_device结构体添加到了内
核的设备列表中了;
3,nor flash在内核中的驱动有两种,一个是cfi_chipdrv,一个是jedec_chipdrv。两种驱动
在我的配置中都在系统时加载了,分别可以在 drivers/mtd/chips/cfi_probe.c 中的
int __init cfi_probe_init()和drivers/mtd/chips/jedec_probe.c 中的
int __init jedec_probe_init()中发现,都调用了
register_mtd_chip_driver(struct mtd_chip_driver *) 在内核中注册了这两个驱动。
4,而真正与nor flash的platform_device对应的platform_driver是定义在
drivers/mtd/maps/physmap.c中,为 struct platform_driver physmap_flash_driver。
该结构体中定义了驱动的名字(name),该变量应该与先前已经通过调用
platform_device_register()注册到内核设备列表中的nor flash设备的那个
struct platform_device dk_flash中的名字一样,这样physmap驱动才能在内核设备列表
中找到相应的设备以获得设备的资源等信息;同时该结构体中有定义了probe函数,该函数
会在platform_driver_register()中被调用,来侦测硬件设备。该驱动在系统启动时被加
载,驱动模块的初始化函数为 int __init physmap_init(),该函数中调用
platform_driver_register(struct platform_drier *)来注册驱动。
5,在 platform_driver_register()注册过程中,会调用参数结构体中的probe函数来侦测
硬件设备,这里为physmap.c中的
int physmap_flash_probe(struct platform_device *dev),其中函数的参数为在该
probe函数被调用前,在platform_driver_register()中通过platform_driver结构体中的
name变量与内核设备列表中已注册了的platform_device的结构体中的name进行匹配,从
而得到的platfor_device。因此,如果platform_device和platform_driver中的name不
一致的话,驱动是不会可能加载成功的。
6,在驱动的侦测函数physmap_flash_probe()中,比较重要的结构体为physmap_flash_info
结构体和physmap_flash_data结构体。其中physmap_flash_info中包含了很重要的信息,
包括了: struct mtd_info *, struct map_info, struct resource,如果有分区的话,
还有 struct mtd_partition *。首先先根据得到的platform_device结构体,将设备
硬件信息设置到驱动结构体中去,即初始化physmap_flash_info中的各个成员。然后,
调用 do_map_probe(char *name, struct map_info *map)来进行实质性的侦测。其中的
参数 name 来自physmap.c中的字符串数组 char *rom_probe_types[]; 这里有三个成员,
表示三种类型的nor flash,分别为"cfi_probe", "jedec_probe"和"map_rom",数组以
NULL表示结束。其实已经知道我们的nor flash SST39VF6401B为jedec类型的了,那么
接下来就直接讲解jedec类型的侦测了,虽然前面有进行了cfi类型的侦测。另一个参数
struct map_info *map则是此前根据硬件信息初始化好的结构体,该结构体在mtd体系
中扮演着十分重要的角色。
7,do_map_probe()定义在drivers/mtd/chips/chipreg.c中,看名字有知道是和芯片注册
相关的一个函数。该函数中有两个主要的结构体: struct mtd_chip_driver *,
struct mtd_info *,都是mtd体系中的重要角色。首先,函数调用get_mtd_chip_driver
函数来取得mtd_chip_driver的指针,而name参数则是上面rom_probe_types中的成员,
这里就以"jedec_probe"来说明。其实和platform_device和platform_driver这中
platform系的驱动一样,也是通过name匹配来找到彼此的。这里就通过"jedec_probe"
这个名字找到了mtd_chip_driver类型的驱动。而这个驱动是在"3"中说明了的,已经在
系统启动时已经通过调用register_mtd_chip_driver()在内核中注册好了的
jedec_chipdrv。
8,在得到了jedec_chipdrv这个驱动结构体指针之后,随即调用该驱动的probe函数,这个
probe函数定义了driver/mtd/chips/jedec_probe.c中,为
struct mtd_info *jedec_probe(struct map_info *map),这个是在驱动结构体里的
probe变量中指定了的。这个函数很干脆,直接就调用了.../gen_probe.c中定义的通
用的侦测函数 struct mtd_info *mtd_do_chip_probe(struct map_info *map,
struct chip_probe *cp),至于原因,注释上说了。
9,在通用的mtd_do_chip_probe()中,有一个比较重要的结构体 struct cfi_private *cfi,
这个结构体在后面的具体的侦测中有用。该函数为了分配这个结构体首先调用
struct cfi_private *genprobe_ident_chips(struct map_info *map,
struct chip_probe *cp),genprobe_ident_chips()中调用
int genprobe_new_chip(struct map_info *, struct chip_probe *,
struct cfi_private *);该函数为了配置cfi,又调用了 struct chip_probe *cp的成员
probe_chip来真正的侦测芯片,看看软件内的配置是否与硬件上的配置一致。这个
struct chip_probe *cp呢,又是在遥远的jedec_probe()函数中被传进来的参数
jedec_chip_probe的指针,参看"8"。这个结构体定义在jedec_probe.c中,结构体的
probe_chip成员指定给了 int jedec_probe_chip(struct map_info *, __u32,
unsigned long *, struct cfi_private *);
10,这个jedec_probe_chip()函数就以符合jedec规格的侦测方法来侦测硬件了。
其中base参数为nor flash的基地址,为0。首先是通过函数cfi_send_gen_cmd()将查询
software ID的Data 和 Addr传输给flash,然后通过jedec_read_mfr()和
jedec_read_id()取得了芯片的制造商代号和芯片id。然后调用jedec_match()测试是否
与已有的芯片符合。这个"已有的芯片"指的是该文件内定义的超长的数组
struct amd_flash_info jedec_table[]。该数组的类型结构体定义了各个制造商的各种
芯片。(唉,AMD和Intel就搞两个标准,烦)。因为内核源码中没有定义这个板子上用的
SST39VF6401B,所以要按照格式(有这么多呢)将参数添加进一个数组成员。如下:
}, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39VF6401,
.name = "SST 39VF6401",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA,
[1] = MTD_UADDR_0x5555_0x2AAA
},
.DevSize = SIZE_8MiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x1000, 2048)
}
同时,要在一堆的宏定义里面找到 SST的里面添上宏:
#define SST39VF6401 0x236d
这个0x236d即为芯片的id,从datasheet中可以知道,同时会在侦测中与从芯片里得到的
id进行匹配。但是datasheet看到的是0x236b,不是这个,不知道为什么。
11,在jedec_match()中将从硬件得到的mfc和id与那个巨大的数组内的各个成员进行匹配
以及进行一些测试。符合要求之后返回之后,就算找到了硬件了,之后进行的东西就是
在内核里面设置好合适的结构体了,然后玩成了physmap这个驱动的注册。完成注册后,
应该就完成了mtd系统中的相关设置(我不确定),关于后面如何使用驱动这个就暂不讲了。
plus: 在"11"里面,完成硬件侦测之后,会在gen_probe.c中调用check_cmd_set(),该函数
中再根据条件调用不同的函数来设置mtd_info结构体里的各种函数,包括read,
write, erase等成员。这里的转到了cfi_cmdset_0002.c里面的cfi_cmdset_0002()函
数,再调用cfi_amdstd_setup。
/* 可能底层的读写函数定义在map.h */
可能是inline_map_read, inline_map_write
mtd的write, read完成时序,比如cfi_amdstd_write_words,并且在该过程中调用
map的read, write完成总线送数据,比如map_read。
更多推荐
已为社区贡献3条内容
所有评论(0)