Skip to content

Commit 8c8d25d

Browse files
committed
Merge tag 'spi-nor/for-6.9' into mtd/next
SPI NOR gets the non uniform erase code cleaned. We stopped using bitmasks for erase types and flags, and instead introduced dedicated members. We then passed the SPI NOR erase map to MTD. Users can now determine the erase regions and make informed decisions on partitions size.
2 parents 77bf032 + 6a9eda3 commit 8c8d25d

File tree

5 files changed

+128
-165
lines changed

5 files changed

+128
-165
lines changed

Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ properties:
5252
minItems: 1
5353
maxItems: 2
5454

55+
interrupts:
56+
maxItems: 1
57+
5558
m25p,fast-read:
5659
type: boolean
5760
description:

drivers/mtd/spi-nor/core.c

Lines changed: 88 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode)
11581158

11591159
static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
11601160
{
1161-
return !!nor->params->erase_map.uniform_erase_type;
1161+
return !!nor->params->erase_map.uniform_region.erase_mask;
11621162
}
11631163

11641164
static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
@@ -1542,24 +1542,22 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
15421542
const struct spi_nor_erase_type *erase;
15431543
u32 rem;
15441544
int i;
1545-
u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
15461545

15471546
/*
15481547
* Erase types are ordered by size, with the smallest erase type at
15491548
* index 0.
15501549
*/
15511550
for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
15521551
/* Does the erase region support the tested erase type? */
1553-
if (!(erase_mask & BIT(i)))
1552+
if (!(region->erase_mask & BIT(i)))
15541553
continue;
15551554

15561555
erase = &map->erase_type[i];
15571556
if (!erase->size)
15581557
continue;
15591558

15601559
/* Alignment is not mandatory for overlaid regions */
1561-
if (region->offset & SNOR_OVERLAID_REGION &&
1562-
region->size <= len)
1560+
if (region->overlaid && region->size <= len)
15631561
return erase;
15641562

15651563
/* Don't erase more than what the user has asked for. */
@@ -1574,59 +1572,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
15741572
return NULL;
15751573
}
15761574

1577-
static u64 spi_nor_region_is_last(const struct spi_nor_erase_region *region)
1578-
{
1579-
return region->offset & SNOR_LAST_REGION;
1580-
}
1581-
1582-
static u64 spi_nor_region_end(const struct spi_nor_erase_region *region)
1583-
{
1584-
return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
1585-
}
1586-
1587-
/**
1588-
* spi_nor_region_next() - get the next spi nor region
1589-
* @region: pointer to a structure that describes a SPI NOR erase region
1590-
*
1591-
* Return: the next spi nor region or NULL if last region.
1592-
*/
1593-
struct spi_nor_erase_region *
1594-
spi_nor_region_next(struct spi_nor_erase_region *region)
1595-
{
1596-
if (spi_nor_region_is_last(region))
1597-
return NULL;
1598-
region++;
1599-
return region;
1600-
}
1601-
1602-
/**
1603-
* spi_nor_find_erase_region() - find the region of the serial flash memory in
1604-
* which the offset fits
1605-
* @map: the erase map of the SPI NOR
1606-
* @addr: offset in the serial flash memory
1607-
*
1608-
* Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno)
1609-
* otherwise.
1610-
*/
1611-
static struct spi_nor_erase_region *
1612-
spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr)
1613-
{
1614-
struct spi_nor_erase_region *region = map->regions;
1615-
u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
1616-
u64 region_end = region_start + region->size;
1617-
1618-
while (addr < region_start || addr >= region_end) {
1619-
region = spi_nor_region_next(region);
1620-
if (!region)
1621-
return ERR_PTR(-EINVAL);
1622-
1623-
region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
1624-
region_end = region_start + region->size;
1625-
}
1626-
1627-
return region;
1628-
}
1629-
16301575
/**
16311576
* spi_nor_init_erase_cmd() - initialize an erase command
16321577
* @region: pointer to a structure that describes a SPI NOR erase region
@@ -1649,7 +1594,7 @@ spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
16491594
cmd->opcode = erase->opcode;
16501595
cmd->count = 1;
16511596

1652-
if (region->offset & SNOR_OVERLAID_REGION)
1597+
if (region->overlaid)
16531598
cmd->size = region->size;
16541599
else
16551600
cmd->size = erase->size;
@@ -1693,44 +1638,36 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
16931638
struct spi_nor_erase_region *region;
16941639
struct spi_nor_erase_command *cmd = NULL;
16951640
u64 region_end;
1641+
unsigned int i;
16961642
int ret = -EINVAL;
16971643

1698-
region = spi_nor_find_erase_region(map, addr);
1699-
if (IS_ERR(region))
1700-
return PTR_ERR(region);
1644+
for (i = 0; i < map->n_regions && len; i++) {
1645+
region = &map->regions[i];
1646+
region_end = region->offset + region->size;
17011647

1702-
region_end = spi_nor_region_end(region);
1703-
1704-
while (len) {
1705-
erase = spi_nor_find_best_erase_type(map, region, addr, len);
1706-
if (!erase)
1707-
goto destroy_erase_cmd_list;
1708-
1709-
if (prev_erase != erase ||
1710-
erase->size != cmd->size ||
1711-
region->offset & SNOR_OVERLAID_REGION) {
1712-
cmd = spi_nor_init_erase_cmd(region, erase);
1713-
if (IS_ERR(cmd)) {
1714-
ret = PTR_ERR(cmd);
1648+
while (len && addr >= region->offset && addr < region_end) {
1649+
erase = spi_nor_find_best_erase_type(map, region, addr,
1650+
len);
1651+
if (!erase)
17151652
goto destroy_erase_cmd_list;
1716-
}
1717-
1718-
list_add_tail(&cmd->list, erase_list);
1719-
} else {
1720-
cmd->count++;
1721-
}
17221653

1723-
addr += cmd->size;
1724-
len -= cmd->size;
1654+
if (prev_erase != erase || erase->size != cmd->size ||
1655+
region->overlaid) {
1656+
cmd = spi_nor_init_erase_cmd(region, erase);
1657+
if (IS_ERR(cmd)) {
1658+
ret = PTR_ERR(cmd);
1659+
goto destroy_erase_cmd_list;
1660+
}
1661+
1662+
list_add_tail(&cmd->list, erase_list);
1663+
} else {
1664+
cmd->count++;
1665+
}
17251666

1726-
if (len && addr >= region_end) {
1727-
region = spi_nor_region_next(region);
1728-
if (!region)
1729-
goto destroy_erase_cmd_list;
1730-
region_end = spi_nor_region_end(region);
1667+
len -= cmd->size;
1668+
addr += cmd->size;
1669+
prev_erase = erase;
17311670
}
1732-
1733-
prev_erase = erase;
17341671
}
17351672

17361673
return 0;
@@ -2468,12 +2405,11 @@ void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase)
24682405
void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
24692406
u8 erase_mask, u64 flash_size)
24702407
{
2471-
/* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */
2472-
map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
2473-
SNOR_LAST_REGION;
2408+
map->uniform_region.offset = 0;
24742409
map->uniform_region.size = flash_size;
2410+
map->uniform_region.erase_mask = erase_mask;
24752411
map->regions = &map->uniform_region;
2476-
map->uniform_erase_type = erase_mask;
2412+
map->n_regions = 1;
24772413
}
24782414

24792415
int spi_nor_post_bfpt_fixups(struct spi_nor *nor,
@@ -2560,7 +2496,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map)
25602496
{
25612497
const struct spi_nor_erase_type *tested_erase, *erase = NULL;
25622498
int i;
2563-
u8 uniform_erase_type = map->uniform_erase_type;
2499+
u8 uniform_erase_type = map->uniform_region.erase_mask;
25642500

25652501
/*
25662502
* Search for the biggest erase size, except for when compiled
@@ -2599,8 +2535,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map)
25992535
return NULL;
26002536

26012537
/* Disable all other Sector Erase commands. */
2602-
map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK;
2603-
map->uniform_erase_type |= BIT(erase - map->erase_type);
2538+
map->uniform_region.erase_mask = BIT(erase - map->erase_type);
26042539
return erase;
26052540
}
26062541

@@ -3434,7 +3369,54 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
34343369
return info;
34353370
}
34363371

3437-
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)
34383420
{
34393421
struct mtd_info *mtd = &nor->mtd;
34403422
struct device *dev = nor->dev;
@@ -3465,6 +3447,11 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
34653447
mtd->_resume = spi_nor_resume;
34663448
mtd->_get_device = spi_nor_get_device;
34673449
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;
34683455
}
34693456

34703457
static int spi_nor_hw_reset(struct spi_nor *nor)
@@ -3555,7 +3542,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
35553542
return ret;
35563543

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

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

drivers/mtd/spi-nor/core.h

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -240,27 +240,21 @@ struct spi_nor_erase_command {
240240
/**
241241
* struct spi_nor_erase_region - Structure to describe a SPI NOR erase region
242242
* @offset: the offset in the data array of erase region start.
243-
* LSB bits are used as a bitmask encoding flags to
244-
* determine if this region is overlaid, if this region is
245-
* the last in the SPI NOR flash memory and to indicate
246-
* all the supported erase commands inside this region.
247-
* The erase types are sorted in ascending order with the
248-
* smallest Erase Type size being at BIT(0).
249243
* @size: the size of the region in bytes.
244+
* @erase_mask: bitmask to indicate all the supported erase commands
245+
* inside this region. The erase types are sorted in
246+
* ascending order with the smallest Erase Type size being
247+
* at BIT(0).
248+
* @overlaid: determine if this region is overlaid.
250249
*/
251250
struct spi_nor_erase_region {
252251
u64 offset;
253252
u64 size;
253+
u8 erase_mask;
254+
bool overlaid;
254255
};
255256

256257
#define SNOR_ERASE_TYPE_MAX 4
257-
#define SNOR_ERASE_TYPE_MASK GENMASK_ULL(SNOR_ERASE_TYPE_MAX - 1, 0)
258-
259-
#define SNOR_LAST_REGION BIT(4)
260-
#define SNOR_OVERLAID_REGION BIT(5)
261-
262-
#define SNOR_ERASE_FLAGS_MAX 6
263-
#define SNOR_ERASE_FLAGS_MASK GENMASK_ULL(SNOR_ERASE_FLAGS_MAX - 1, 0)
264258

265259
/**
266260
* struct spi_nor_erase_map - Structure to describe the SPI NOR erase map
@@ -273,17 +267,13 @@ struct spi_nor_erase_region {
273267
* The erase types are sorted in ascending order, with the
274268
* smallest Erase Type size being the first member in the
275269
* erase_type array.
276-
* @uniform_erase_type: bitmask encoding erase types that can erase the
277-
* entire memory. This member is completed at init by
278-
* uniform and non-uniform SPI NOR flash memories if they
279-
* support at least one erase type that can erase the
280-
* entire memory.
270+
* @n_regions: number of erase regions.
281271
*/
282272
struct spi_nor_erase_map {
283273
struct spi_nor_erase_region *regions;
284274
struct spi_nor_erase_region uniform_region;
285275
struct spi_nor_erase_type erase_type[SNOR_ERASE_TYPE_MAX];
286-
u8 uniform_erase_type;
276+
unsigned int n_regions;
287277
};
288278

289279
/**
@@ -675,8 +665,6 @@ void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode,
675665
void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size,
676666
u8 opcode);
677667
void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase);
678-
struct spi_nor_erase_region *
679-
spi_nor_region_next(struct spi_nor_erase_region *region);
680668
void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
681669
u8 erase_mask, u64 flash_size);
682670

0 commit comments

Comments
 (0)