From 0a57265533c412adf6024f4b4955141f4346b2b9 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 12 May 2009 14:29:39 +0200 Subject: mtd: Add MTD concat support to concatenate multiple MTD NOR devices This patch adds concatenation support to the U-Boot MTD infrastructure. By enabling CONFIG_MTD_CONCAT this MTD CFI wrapper will concatenate all found NOR devices into one single MTD device. This can be used by e.g by UBI to access a partition that spans over multiple NOR chips. Signed-off-by: Stefan Roese --- drivers/mtd/cfi_mtd.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/cfi_mtd.c') diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index 4a76917ac3..300517e869 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -25,14 +25,19 @@ #include #include +#include #include #include +#include extern flash_info_t flash_info[]; static struct mtd_info cfi_mtd_info[CONFIG_SYS_MAX_FLASH_BANKS]; static char cfi_mtd_names[CONFIG_SYS_MAX_FLASH_BANKS][16]; +#ifdef CONFIG_MTD_CONCAT +static char c_mtd_name[16]; +#endif static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { @@ -145,16 +150,68 @@ static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi) { int sect_size = 0; + int sect_size_old = 0; int sect; + int regions = 0; + int numblocks = 0; + ulong offset = 0; + ulong base_addr = fi->start[0]; /* - * Select the largest sector size as erasesize (e.g. for UBI) + * First detect the number of eraseregions so that we can allocate + * the array of eraseregions correctly */ for (sect = 0; sect < fi->sector_count; sect++) { + if (sect_size_old != flash_sector_size(fi, sect)) + regions++; + sect_size_old = flash_sector_size(fi, sect); + } + + mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info) * regions); + + /* + * Now detect the largest sector and fill the eraseregions + */ + sect_size_old = 0; + regions = 0; + for (sect = 0; sect < fi->sector_count; sect++) { + if ((sect_size_old != flash_sector_size(fi, sect)) && + (sect_size_old != 0)) { + mtd->eraseregions[regions].offset = offset - base_addr; + mtd->eraseregions[regions].erasesize = sect_size_old; + mtd->eraseregions[regions].numblocks = numblocks; + + /* Now start counting the next eraseregions */ + numblocks = 0; + regions++; + } else { + numblocks++; + } + + if (sect_size_old != flash_sector_size(fi, sect)) + offset = fi->start[sect]; + + /* + * Select the largest sector size as erasesize (e.g. for UBI) + */ if (flash_sector_size(fi, sect) > sect_size) sect_size = flash_sector_size(fi, sect); + + sect_size_old = flash_sector_size(fi, sect); } + /* + * Set the last region + */ + mtd->eraseregions[regions].offset = offset - base_addr; + mtd->eraseregions[regions].erasesize = sect_size_old; + mtd->eraseregions[regions].numblocks = numblocks + 1; + + if (regions) + mtd->numeraseregions = regions + 1; + else + mtd->numeraseregions = 0; + mtd->erasesize = sect_size; return 0; @@ -165,6 +222,8 @@ int cfi_mtd_init(void) struct mtd_info *mtd; flash_info_t *fi; int error, i; + int devices_found = 0; + struct mtd_info *mtd_list[CONFIG_SYS_MAX_FLASH_BANKS]; for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { fi = &flash_info[i]; @@ -193,7 +252,25 @@ int cfi_mtd_init(void) if (add_mtd_device(mtd)) return -ENOMEM; + + mtd_list[devices_found++] = mtd; + } + +#ifdef CONFIG_MTD_CONCAT + if (devices_found > 1) { + /* + * We detected multiple devices. Concatenate them together. + */ + sprintf(c_mtd_name, "nor%d", devices_found); + mtd = mtd_concat_create(mtd_list, devices_found, c_mtd_name); + + if (mtd == NULL) + return -ENXIO; + + if (add_mtd_device(mtd)) + return -ENOMEM; } +#endif /* CONFIG_MTD_CONCAT */ return 0; } -- cgit v1.2.1