Skip to content

Commit 6a9eda3

Browse files
Kuwano-sanambarus
authored andcommitted
mtd: spi-nor: core: set mtd->eraseregions for non-uniform erase map
Some of Infineon SPI NOR flash devices support hybrid sector layout that overlays 4KB sectors on a 256KB sector and SPI NOR framework recognizes that by parsing SMPT and construct params->erase_map. The hybrid sector layout is similar to CFI flash devices that have small sectors on top and/or bottom address. In case of CFI flash devices, the erase map information is parsed through CFI table and populated into mtd->eraseregions so that users can create MTD partitions that aligned with small sector boundaries. This patch provides the same capability to SPI NOR flash devices that have non-uniform erase map. Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com> Reviewed-by: Michael Walle <mwalle@kernel.org> Link: https://lore.kernel.org/r/35d0962986e493b06c13bdf7ada8130a9966dc02.1708404584.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
1 parent 2865ed0 commit 6a9eda3

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

drivers/mtd/spi-nor/core.c

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,7 +3369,54 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
33693369
return info;
33703370
}
33713371

3372-
static void spi_nor_set_mtd_info(struct spi_nor *nor)
3372+
static u32
3373+
spi_nor_get_region_erasesize(const struct spi_nor_erase_region *region,
3374+
const struct spi_nor_erase_type *erase_type)
3375+
{
3376+
u8 i;
3377+
3378+
if (region->overlaid)
3379+
return region->size;
3380+
3381+
for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
3382+
if (region->erase_mask & BIT(i))
3383+
return erase_type[i].size;
3384+
}
3385+
3386+
return 0;
3387+
}
3388+
3389+
static int spi_nor_set_mtd_eraseregions(struct spi_nor *nor)
3390+
{
3391+
const struct spi_nor_erase_map *map = &nor->params->erase_map;
3392+
const struct spi_nor_erase_region *region = map->regions;
3393+
struct mtd_erase_region_info *mtd_region;
3394+
struct mtd_info *mtd = &nor->mtd;
3395+
u32 erasesize, i;
3396+
3397+
mtd_region = devm_kcalloc(nor->dev, map->n_regions, sizeof(*mtd_region),
3398+
GFP_KERNEL);
3399+
if (!mtd_region)
3400+
return -ENOMEM;
3401+
3402+
for (i = 0; i < map->n_regions; i++) {
3403+
erasesize = spi_nor_get_region_erasesize(&region[i],
3404+
map->erase_type);
3405+
if (!erasesize)
3406+
return -EINVAL;
3407+
3408+
mtd_region[i].erasesize = erasesize;
3409+
mtd_region[i].numblocks = div64_ul(region[i].size, erasesize);
3410+
mtd_region[i].offset = region[i].offset;
3411+
}
3412+
3413+
mtd->numeraseregions = map->n_regions;
3414+
mtd->eraseregions = mtd_region;
3415+
3416+
return 0;
3417+
}
3418+
3419+
static int spi_nor_set_mtd_info(struct spi_nor *nor)
33733420
{
33743421
struct mtd_info *mtd = &nor->mtd;
33753422
struct device *dev = nor->dev;
@@ -3400,6 +3447,11 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
34003447
mtd->_resume = spi_nor_resume;
34013448
mtd->_get_device = spi_nor_get_device;
34023449
mtd->_put_device = spi_nor_put_device;
3450+
3451+
if (!spi_nor_has_uniform_erase(nor))
3452+
return spi_nor_set_mtd_eraseregions(nor);
3453+
3454+
return 0;
34033455
}
34043456

34053457
static int spi_nor_hw_reset(struct spi_nor *nor)
@@ -3490,7 +3542,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
34903542
return ret;
34913543

34923544
/* No mtd_info fields should be used up to this point. */
3493-
spi_nor_set_mtd_info(nor);
3545+
ret = spi_nor_set_mtd_info(nor);
3546+
if (ret)
3547+
return ret;
34943548

34953549
dev_dbg(dev, "Manufacturer and device ID: %*phN\n",
34963550
SPI_NOR_MAX_ID_LEN, nor->id);

0 commit comments

Comments
 (0)