X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fcfi_mtd.c;h=6a0cab3059ba2b0976afa3e6ca85b50c3ed9bc87;hb=09b4a9cf4003599f2cd609587dfa5f0b754640ed;hp=9ac1c86cced3a8d5848c031b153a138cea973211;hpb=712ac6a1a6909a58d6549fb220cc921a7e9f9979;p=u-boot diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index 9ac1c86cce..6a0cab3059 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -25,14 +25,26 @@ #include #include +#include #include #include +#include + +/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */ +#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT +# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT +#else +# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS +#endif 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]; +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) { @@ -43,11 +55,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; } @@ -113,7 +130,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; @@ -125,7 +142,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; @@ -140,26 +157,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; @@ -170,6 +230,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]; @@ -198,7 +260,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; }