Message ID | 35d0962986e493b06c13bdf7ada8130a9966dc02.1708404584.git.Takahiro.Kuwano@infineon.com |
---|---|
State | Accepted |
Delegated to: | Ambarus Tudor |
Headers | show |
Series | mtd: spi-nor: core: set mtd->eraseregions for non-uniform erase map | expand |
On Tue Feb 20, 2024 at 9:34 AM CET, tkuw584924 wrote: > From: Takahiro Kuwano <Takahiro.Kuwano@infineon.com> > > 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> > --- > drivers/mtd/spi-nor/core.c | 58 ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 56 insertions(+), 2 deletions(-) > > diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c > index 21775d5eccd5..5ba570248cb9 100644 > --- a/drivers/mtd/spi-nor/core.c > +++ b/drivers/mtd/spi-nor/core.c > @@ -3349,7 +3349,54 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, > return info; > } > > -static void spi_nor_set_mtd_info(struct spi_nor *nor) > +static u32 > +spi_nor_get_region_erasesize(const struct spi_nor_erase_region *region, > + const struct spi_nor_erase_type *erase_type) > +{ > + u8 i; > + > + if (region->overlaid) > + return region->size; > + > + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { > + if (region->erase_mask & BIT(i)) > + return erase_type[i].size; > + } nit: You could drop the braces. Reviewed-by: Michael Walle <mwalle@kernel.org> -michael
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 21775d5eccd5..5ba570248cb9 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3349,7 +3349,54 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, return info; } -static void spi_nor_set_mtd_info(struct spi_nor *nor) +static u32 +spi_nor_get_region_erasesize(const struct spi_nor_erase_region *region, + const struct spi_nor_erase_type *erase_type) +{ + u8 i; + + if (region->overlaid) + return region->size; + + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (region->erase_mask & BIT(i)) + return erase_type[i].size; + } + + return 0; +} + +static int spi_nor_set_mtd_eraseregions(struct spi_nor *nor) +{ + const struct spi_nor_erase_map *map = &nor->params->erase_map; + const struct spi_nor_erase_region *region = map->regions; + struct mtd_erase_region_info *mtd_region; + struct mtd_info *mtd = &nor->mtd; + u32 erasesize, i; + + mtd_region = devm_kcalloc(nor->dev, map->n_regions, sizeof(*mtd_region), + GFP_KERNEL); + if (!mtd_region) + return -ENOMEM; + + for (i = 0; i < map->n_regions; i++) { + erasesize = spi_nor_get_region_erasesize(®ion[i], + map->erase_type); + if (!erasesize) + return -EINVAL; + + mtd_region[i].erasesize = erasesize; + mtd_region[i].numblocks = div64_ul(region[i].size, erasesize); + mtd_region[i].offset = region[i].offset; + } + + mtd->numeraseregions = map->n_regions; + mtd->eraseregions = mtd_region; + + return 0; +} + +static int spi_nor_set_mtd_info(struct spi_nor *nor) { struct mtd_info *mtd = &nor->mtd; struct device *dev = nor->dev; @@ -3380,6 +3427,11 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->_resume = spi_nor_resume; mtd->_get_device = spi_nor_get_device; mtd->_put_device = spi_nor_put_device; + + if (!spi_nor_has_uniform_erase(nor)) + return spi_nor_set_mtd_eraseregions(nor); + + return 0; } static int spi_nor_hw_reset(struct spi_nor *nor) @@ -3472,7 +3524,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, return ret; /* No mtd_info fields should be used up to this point. */ - spi_nor_set_mtd_info(nor); + ret = spi_nor_set_mtd_info(nor); + if (ret) + return ret; dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10);