开发板上只有Nor Flash,所以为了实现层次文件系统,需要为Linux2.6.20增加Nor Flash MTD驱动支持。其实工作量并不大,因为已经有现成的程序可供参考。
MTD的驱动程序都集中在drivers/mtd里面。我们需要做的,仅仅是在drivers/mtd/maps下增加自己的分区表。因为有参考的代码,所以比较容易。
(1)构建配置选项
首先,根据edb7312.c构建自己的mtd分区表驱动。
$cd drivers/mtd/maps/
$cp edb7312.c at91rm9200.c
然后,修改Kconfig,增加自己的配置选项。
//拷贝过EDB7312稍作修改即可
config MTD_AT91RM9200
tristate "CFI Flash device mapped on AT91RM9200"
depends on ARM && MTD_CFI
help
This enables access to the CFI Flash on the ATMEL AT91RM9200DK board.
If you have such a board, say 'Y' here.
最后,修改Makefile,增加编译项目。
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_AT91RM9200) += at91rm9200.o
这样,自己建立的MTD分区表驱动就可以编译进内核了。
(2)修改分区表信息
因为第一步的工作中,at91rm9200.c实际上还是edb7312.c的内容,所以需要根据自己的开发板nor flash的配置做一下修改。
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_MTD_PARTITIONS
#include
#endif
#define WINDOW_ADDR 0x10000000 /* physical properties of flash */
#define WINDOW_SIZE 0x00800000 /* intel 28F640J3A 8MB */
#define BUSWIDTH 2 /* data bus width 16bits */
/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
#define PROBETYPES { "cfi_probe", NULL }
#define MSG_PREFIX "AT91RM9200-NOR:" /* prefix for our printk()'s */
#define MTDID "at91rm9200-%d" /* for mtdparts= partitioning */
static struct mtd_info *mymtd;
struct map_info at91rm9200nor_map = {
.name = "NOR flash on AT91RM9200DK",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
};
#ifdef CONFIG_MTD_PARTITIONS
/*
* MTD partitioning stuff
*/
static struct mtd_partition at91rm9200nor_partitions[5] =
{
{
// U-boot 128KB
.name = "U-boot",
.size = 0x20000,
.offset = 0
},
{
// uImage 2MB
.name = "Kernel",
.size = 0x200000,
.offset = 0x20000
},
{
// RootFS 3MB
.name = "RootFS",
.size = 0x300000,
.offset = 0x220000
},
{
// UserFS
.name = "Jffs2",
.size = 0x2C0000,
.offset = 0x520000
},
{
// Parameters
.name = "Parameters",
.size = 0x20000,
.offset = 0x7E0000
},
};
static const char *probes[] = { NULL };
#endif
static int mtd_parts_nb = 0;
static struct mtd_partition *mtd_parts = 0;
int __init init_at91rm9200nor(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
const char *part_type = 0;
printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x/n",
WINDOW_SIZE, WINDOW_ADDR);
at91rm9200nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!at91rm9200nor_map.virt) {
printk(MSG_PREFIX "failed to ioremap/n");
return -EIO;
}
simple_map_init(&at91rm9200nor_map);
mymtd = 0;
type = rom_probe_types;
for(; !mymtd && *type; type++) {
mymtd = do_map_probe(*type, &at91rm9200nor_map);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
if (mtd_parts_nb > 0)
part_type = "detected";
if (mtd_parts_nb == 0)
{
mtd_parts = at91rm9200nor_partitions;
mtd_parts_nb = ARRAY_SIZE(at91rm9200nor_partitions);
part_type = "static";
}
#endif
add_mtd_device(mymtd);
if (mtd_parts_nb == 0)
printk(KERN_NOTICE MSG_PREFIX "no partition info available/n");
else
{
printk(KERN_NOTICE MSG_PREFIX
"using %s partition definition/n", part_type);
add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
}
return 0;
}
iounmap((void *)at91rm9200nor_map.virt);
return -ENXIO;
}
static void __exit cleanup_at91rm9200nor(void)
{
if (mymtd) {
del_mtd_device(mymtd);
map_destroy(mymtd);
}
if (at91rm9200nor_map.virt) {
iounmap((void *)at91rm9200nor_map.virt);
at91rm9200nor_map.virt = 0;
}
}
module_init(init_at91rm9200nor);
module_exit(cleanup_at91rm9200nor);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marius Groeger ");
MODULE_DESCRIPTION("Generic configurable MTD map driver");
(3)配置内核
增加MTD,和相应的文件系统的支持。
Devices Drivers --->
Memory Technology Devices (MTD) --->
Memory Technology Device(MTD) support
MTD partitioning support
Direct char device access to MTD devices
Caching block device access to MTD devices
RAM/ROM/Flash chip drivers --->
Detect flash chips by Common Flash Interface(CFI) probe
Support for Intel/Sharp flash chips
Mapping drivers for chip access --->
CFI Flash device mapped on AT91RM9200
File Systems --->
Miscellaneous filesystems --->
这里选择cramfs或者Jffs2的支持。
(4)编译,然后加载
make Image编译,然后制作成uImage。
TOPDIR=$($(which pwd))
TMP=$TOPDIR/linux.bin
TARGET=$TOPDIR/uImage
arm-linux-objcopy -O binary -S vmlinux $TMP && gzip -v9 $TMP && /
mkimage -n 'RAM disk' -A arm -O linux -T kernel -C gzip /
-a 0x20008000 -e 0x20008000 -d $TMP.gz $TARGET && /
cp $TARGET /mnt/hgfs/common && /
rm -f $TMP*
这是JFFS2作为根文件系统的信息:
AT91RM9200-NOR:0x00800000 at 0x10000000
NOR flash on AT91RM9200DK: Found 1 x16 devices at 0x0 in 16-bit bank
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
cfi_cmdset_0001: Erase suspend on write enabled
AT91RM9200-NOR:using static partition definition
Creating 5 MTD partitions on "NOR flash on AT91RM9200DK":
0x00000000-0x00020000 : "U-boot"
0x00020000-0x00220000 : "Kernel"
0x00220000-0x00520000 : "RootFS"
0x00520000-0x007e0000 : "Jffs2"
0x007e0000-0x00800000 : "Parameters"
JFFS2 notice: (1) jffs2_build_xattr_subsystem: complete building xattr subsystem, 0 of xdatum (0 unchecked, 0 orphan) and 0 of xref (0 dead, 0 orphan) found.
VFS: Mounted root (jffs2 filesystem).
Freeing init memory: 100K
init started: BusyBox v1.9.1 (2008-03-15 15:28:44 CST)
starting pid 710, tty '': '/etc/init.d/rcS'
可以看到MTD分区信息。进入shell界面,然后查看/proc/mtd,如下:
[root@lqm ~]#cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00020000 "NOR flash on AT91RM9200DK"
mtd1: 00020000 00020000 "U-boot"
mtd2: 00200000 00020000 "Kernel"
mtd3: 00300000 00020000 "RootFS"
mtd4: 002c0000 00020000 "Jffs2"
mtd5: 00020000 00020000 "Parameters"
可以看到加载是正确的。
________________________________________
附:MAC地址全零的解决
/*
* Set the ethernet MAC address in dev->dev_addr
*/
static void __init get_mac_address(struct net_device *dev)
{
#if 0
/* Check Specific-Address 1 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
return;
/* Check Specific-Address 2 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
return;
/* Check Specific-Address 3 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
return;
/* Check Specific-Address 4 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
return;
#endif
static char def_mac[] = {0x36, 0xB9, 0x04, 0x00, 0x24, 0x80};
memcpy(dev->dev_addr, def_mac, 6);
printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address./n");
}
位置是drivers/net/arm/at91_ether.c。这样就获得临时解决了。
MTD的驱动程序都集中在drivers/mtd里面。我们需要做的,仅仅是在drivers/mtd/maps下增加自己的分区表。因为有参考的代码,所以比较容易。
(1)构建配置选项
首先,根据edb7312.c构建自己的mtd分区表驱动。
$cd drivers/mtd/maps/
$cp edb7312.c at91rm9200.c
然后,修改Kconfig,增加自己的配置选项。
//拷贝过EDB7312稍作修改即可
config MTD_AT91RM9200
tristate "CFI Flash device mapped on AT91RM9200"
depends on ARM && MTD_CFI
help
This enables access to the CFI Flash on the ATMEL AT91RM9200DK board.
If you have such a board, say 'Y' here.
最后,修改Makefile,增加编译项目。
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_AT91RM9200) += at91rm9200.o
这样,自己建立的MTD分区表驱动就可以编译进内核了。
(2)修改分区表信息
因为第一步的工作中,at91rm9200.c实际上还是edb7312.c的内容,所以需要根据自己的开发板nor flash的配置做一下修改。
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_MTD_PARTITIONS
#include
#endif
#define WINDOW_ADDR 0x10000000 /* physical properties of flash */
#define WINDOW_SIZE 0x00800000 /* intel 28F640J3A 8MB */
#define BUSWIDTH 2 /* data bus width 16bits */
/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
#define PROBETYPES { "cfi_probe", NULL }
#define MSG_PREFIX "AT91RM9200-NOR:" /* prefix for our printk()'s */
#define MTDID "at91rm9200-%d" /* for mtdparts= partitioning */
static struct mtd_info *mymtd;
struct map_info at91rm9200nor_map = {
.name = "NOR flash on AT91RM9200DK",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
};
#ifdef CONFIG_MTD_PARTITIONS
/*
* MTD partitioning stuff
*/
static struct mtd_partition at91rm9200nor_partitions[5] =
{
{
// U-boot 128KB
.name = "U-boot",
.size = 0x20000,
.offset = 0
},
{
// uImage 2MB
.name = "Kernel",
.size = 0x200000,
.offset = 0x20000
},
{
// RootFS 3MB
.name = "RootFS",
.size = 0x300000,
.offset = 0x220000
},
{
// UserFS
.name = "Jffs2",
.size = 0x2C0000,
.offset = 0x520000
},
{
// Parameters
.name = "Parameters",
.size = 0x20000,
.offset = 0x7E0000
},
};
static const char *probes[] = { NULL };
#endif
static int mtd_parts_nb = 0;
static struct mtd_partition *mtd_parts = 0;
int __init init_at91rm9200nor(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
const char *part_type = 0;
printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x/n",
WINDOW_SIZE, WINDOW_ADDR);
at91rm9200nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!at91rm9200nor_map.virt) {
printk(MSG_PREFIX "failed to ioremap/n");
return -EIO;
}
simple_map_init(&at91rm9200nor_map);
mymtd = 0;
type = rom_probe_types;
for(; !mymtd && *type; type++) {
mymtd = do_map_probe(*type, &at91rm9200nor_map);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
if (mtd_parts_nb > 0)
part_type = "detected";
if (mtd_parts_nb == 0)
{
mtd_parts = at91rm9200nor_partitions;
mtd_parts_nb = ARRAY_SIZE(at91rm9200nor_partitions);
part_type = "static";
}
#endif
add_mtd_device(mymtd);
if (mtd_parts_nb == 0)
printk(KERN_NOTICE MSG_PREFIX "no partition info available/n");
else
{
printk(KERN_NOTICE MSG_PREFIX
"using %s partition definition/n", part_type);
add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
}
return 0;
}
iounmap((void *)at91rm9200nor_map.virt);
return -ENXIO;
}
static void __exit cleanup_at91rm9200nor(void)
{
if (mymtd) {
del_mtd_device(mymtd);
map_destroy(mymtd);
}
if (at91rm9200nor_map.virt) {
iounmap((void *)at91rm9200nor_map.virt);
at91rm9200nor_map.virt = 0;
}
}
module_init(init_at91rm9200nor);
module_exit(cleanup_at91rm9200nor);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marius Groeger ");
MODULE_DESCRIPTION("Generic configurable MTD map driver");
(3)配置内核
增加MTD,和相应的文件系统的支持。
Devices Drivers --->
Memory Technology Devices (MTD) --->
Memory Technology Device(MTD) support
MTD partitioning support
Direct char device access to MTD devices
Caching block device access to MTD devices
RAM/ROM/Flash chip drivers --->
Detect flash chips by Common Flash Interface(CFI) probe
Support for Intel/Sharp flash chips
Mapping drivers for chip access --->
CFI Flash device mapped on AT91RM9200
File Systems --->
Miscellaneous filesystems --->
这里选择cramfs或者Jffs2的支持。
(4)编译,然后加载
make Image编译,然后制作成uImage。
TOPDIR=$($(which pwd))
TMP=$TOPDIR/linux.bin
TARGET=$TOPDIR/uImage
arm-linux-objcopy -O binary -S vmlinux $TMP && gzip -v9 $TMP && /
mkimage -n 'RAM disk' -A arm -O linux -T kernel -C gzip /
-a 0x20008000 -e 0x20008000 -d $TMP.gz $TARGET && /
cp $TARGET /mnt/hgfs/common && /
rm -f $TMP*
这是JFFS2作为根文件系统的信息:
AT91RM9200-NOR:0x00800000 at 0x10000000
NOR flash on AT91RM9200DK: Found 1 x16 devices at 0x0 in 16-bit bank
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
cfi_cmdset_0001: Erase suspend on write enabled
AT91RM9200-NOR:using static partition definition
Creating 5 MTD partitions on "NOR flash on AT91RM9200DK":
0x00000000-0x00020000 : "U-boot"
0x00020000-0x00220000 : "Kernel"
0x00220000-0x00520000 : "RootFS"
0x00520000-0x007e0000 : "Jffs2"
0x007e0000-0x00800000 : "Parameters"
JFFS2 notice: (1) jffs2_build_xattr_subsystem: complete building xattr subsystem, 0 of xdatum (0 unchecked, 0 orphan) and 0 of xref (0 dead, 0 orphan) found.
VFS: Mounted root (jffs2 filesystem).
Freeing init memory: 100K
init started: BusyBox v1.9.1 (2008-03-15 15:28:44 CST)
starting pid 710, tty '': '/etc/init.d/rcS'
可以看到MTD分区信息。进入shell界面,然后查看/proc/mtd,如下:
[root@lqm ~]#cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00020000 "NOR flash on AT91RM9200DK"
mtd1: 00020000 00020000 "U-boot"
mtd2: 00200000 00020000 "Kernel"
mtd3: 00300000 00020000 "RootFS"
mtd4: 002c0000 00020000 "Jffs2"
mtd5: 00020000 00020000 "Parameters"
可以看到加载是正确的。
________________________________________
附:MAC地址全零的解决
/*
* Set the ethernet MAC address in dev->dev_addr
*/
static void __init get_mac_address(struct net_device *dev)
{
#if 0
/* Check Specific-Address 1 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
return;
/* Check Specific-Address 2 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
return;
/* Check Specific-Address 3 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
return;
/* Check Specific-Address 4 */
if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
return;
#endif
static char def_mac[] = {0x36, 0xB9, 0x04, 0x00, 0x24, 0x80};
memcpy(dev->dev_addr, def_mac, 6);
printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address./n");
}
位置是drivers/net/arm/at91_ether.c。这样就获得临时解决了。