summaryrefslogtreecommitdiff
path: root/drivers/mtd/cfi_mtd.c
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2009-05-12 14:29:39 +0200
committerWolfgang Denk <wd@denx.de>2009-06-12 20:45:47 +0200
commit0a57265533c412adf6024f4b4955141f4346b2b9 (patch)
tree011c00b2cfb16aa1cb9e01f2938d7664209c4f2c /drivers/mtd/cfi_mtd.c
parent55e0ed6078b10b0d425b6a0677f38a015c277df6 (diff)
downloadu-boot-imx-0a57265533c412adf6024f4b4955141f4346b2b9.zip
u-boot-imx-0a57265533c412adf6024f4b4955141f4346b2b9.tar.gz
u-boot-imx-0a57265533c412adf6024f4b4955141f4346b2b9.tar.bz2
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 <sr@denx.de>
Diffstat (limited to 'drivers/mtd/cfi_mtd.c')
-rw-r--r--drivers/mtd/cfi_mtd.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c
index 4a76917..300517e 100644
--- a/drivers/mtd/cfi_mtd.c
+++ b/drivers/mtd/cfi_mtd.c
@@ -25,14 +25,19 @@
#include <common.h>
#include <flash.h>
+#include <malloc.h>
#include <asm/errno.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
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;
}