X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fcfi_mtd.c;h=8d74fa94128a7348de33a4051ba3ef3f13d805a6;hb=419a1fe95497688cf2129472acf3158c24e96ad4;hp=cf82d92788647ddb5deb55d83a9eee511ff80f36;hpb=be4880ebe4355e8782be4af4b337a1b98dffcbe3;p=u-boot diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index cf82d92788..8d74fa9412 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -25,13 +25,18 @@ #include #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 struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS]; +static char cfi_mtd_names[CFI_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) { @@ -42,11 +47,16 @@ static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int s_last = -1; int error, sect; - for (sect = 0; sect < fi->sector_count - 1; sect++) { + for (sect = 0; sect < fi->sector_count; sect++) { if (a_start == fi->start[sect]) s_first = sect; - if (a_end == fi->start[sect + 1]) { + if (sect < fi->sector_count - 1) { + if (a_end == fi->start[sect + 1]) { + s_last = sect; + break; + } + } else { s_last = sect; break; } @@ -112,7 +122,7 @@ static void cfi_mtd_sync(struct mtd_info *mtd) */ } -static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { flash_info_t *fi = mtd->priv; @@ -124,7 +134,7 @@ static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return 0; } -static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { flash_info_t *fi = mtd->priv; @@ -139,26 +149,69 @@ 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; + ulong base_addr; + /* + * 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) { - sect_size = flash_sector_size(fi, sect); - continue; - } + if (sect_size_old != flash_sector_size(fi, sect)) + regions++; + sect_size_old = flash_sector_size(fi, sect); + } - if (sect_size != flash_sector_size(fi, sect)) { - sect_size = 0; - break; - } + switch (regions) { + case 0: + return 1; + case 1: /* flash has uniform erase size */ + mtd->numeraseregions = 0; + mtd->erasesize = sect_size_old; + return 0; } - if (!sect_size) { - puts("cfi-mtd: devices with multiple sector sizes are" - "not supported\n"); - return -EINVAL; + mtd->numeraseregions = regions; + mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info) * regions); + + /* + * Now detect the largest sector and fill the eraseregions + */ + regions = 0; + base_addr = offset = fi->start[0]; + sect_size_old = flash_sector_size(fi, 0); + for (sect = 0; sect < fi->sector_count; sect++) { + if (sect_size_old != flash_sector_size(fi, sect)) { + 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++; + offset = fi->start[sect]; + } + numblocks++; + + /* + * 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; + mtd->erasesize = sect_size; return 0; @@ -169,6 +222,10 @@ int cfi_mtd_init(void) struct mtd_info *mtd; flash_info_t *fi; int error, i; +#ifdef CONFIG_MTD_CONCAT + int devices_found = 0; + struct mtd_info *mtd_list[CONFIG_SYS_MAX_FLASH_BANKS]; +#endif for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { fi = &flash_info[i]; @@ -180,7 +237,8 @@ int cfi_mtd_init(void) if (error) continue; - mtd->name = CFI_MTD_DEV_NAME; + sprintf(cfi_mtd_names[i], "nor%d", i); + mtd->name = cfi_mtd_names[i]; mtd->type = MTD_NORFLASH; mtd->flags = MTD_CAP_NORFLASH; mtd->size = fi->size; @@ -196,7 +254,27 @@ int cfi_mtd_init(void) if (add_mtd_device(mtd)) return -ENOMEM; + +#ifdef CONFIG_MTD_CONCAT + mtd_list[devices_found++] = mtd; +#endif + } + +#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; }